/* Camofi landing page — component & layout styles */

body{overflow-x:hidden;background:var(--surface-page)}

.container{max-width:var(--container-max);margin:0 auto;padding:0 40px}

/* ---------- Header ---------- */
.site-header{
  position:fixed;top:0;left:0;right:0;z-index:40;
  display:flex;align-items:center;gap:40px;
  padding:0 40px;height:68px;
  background:var(--glass-fill-strong);
  backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);
  border-bottom:1px solid transparent;
  transition:border-color var(--duration-base) var(--ease-standard),box-shadow var(--duration-base) var(--ease-standard);
}
/* The header earns its edge only once content has scrolled beneath it. */
.site-header.is-scrolled{border-bottom-color:var(--border-subtle);box-shadow:var(--shadow-xs)}
.site-header .logo{display:inline-flex;transition:opacity var(--duration-fast) var(--ease-standard)}
.site-header .logo:hover{opacity:0.62}
.site-header .logo img{display:block;height:22px;width:auto}
.site-nav{display:flex;gap:28px;flex:1}
.site-nav a{
  position:relative;padding:4px 0;
  font-size:var(--text-body-sm);font-weight:var(--weight-medium);color:var(--text-secondary);
  transition:color var(--duration-fast) var(--ease-standard);
}
.site-nav a:hover,.site-nav a:focus-visible{color:var(--text-primary);text-decoration:none}
/* Underline grows from the left rather than snapping in. */
.site-nav a::after{
  content:"";position:absolute;left:0;bottom:0;height:1.5px;width:100%;
  background:var(--camofi-blue);border-radius:2px;
  transform:scaleX(0);transform-origin:left center;
  transition:transform var(--duration-base) var(--ease-standard);
}
.site-nav a:hover::after,.site-nav a:focus-visible::after{transform:scaleX(1)}
/* margin-left:auto, not the nav's flex:1, is what pins these to the right.
   Below 860px .site-nav becomes position:absolute and leaves the flex flow, so
   its flex:1 stops pushing anything — the hamburger fell back to sitting next
   to the logo. This holds at every width. */
.header-actions{display:flex;align-items:center;gap:12px;margin-left:auto}

/* Hamburger — desktop hides it, mobile relies on it. */
.nav-toggle{
  display:none;align-items:center;justify-content:center;
  width:38px;height:38px;padding:0;
  background:transparent;border:1px solid var(--border-default);border-radius:var(--radius-md);
  color:var(--text-primary);cursor:pointer;transition:var(--transition-control);
}
.nav-toggle:hover{background:var(--surface-sunken)}
.nav-toggle-bars{position:relative;display:block;width:17px;height:11px}
.nav-toggle-bars span{
  position:absolute;left:0;width:100%;height:1.5px;border-radius:2px;background:currentColor;
  transition:transform var(--duration-base) var(--ease-standard),opacity var(--duration-fast) var(--ease-standard);
}
.nav-toggle-bars span:nth-child(1){top:0}
.nav-toggle-bars span:nth-child(2){bottom:0}
.nav-toggle[aria-expanded="true"] .nav-toggle-bars span:nth-child(1){transform:translateY(4.75px) rotate(45deg)}
.nav-toggle[aria-expanded="true"] .nav-toggle-bars span:nth-child(2){transform:translateY(-4.75px) rotate(-45deg)}

/* ---------- Buttons ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  height:40px;padding:0 18px;border-radius:var(--radius-pill);
  font-family:var(--font-sans);font-size:var(--text-body-sm);font-weight:var(--weight-medium);
  letter-spacing:var(--tracking-body);white-space:nowrap;cursor:pointer;
  border:1px solid transparent;position:relative;transition:var(--transition-control);
  background:var(--camofi-blue);color:var(--text-inverse);box-shadow:var(--shadow-xs);
}
.btn:hover{background:var(--camofi-blue-hover);color:var(--text-inverse);text-decoration:none}
.btn:active{background:var(--camofi-blue-press);transform:translateY(0.5px);box-shadow:none}
.btn svg{flex:0 0 auto}
.btn-sm{height:32px;padding:0 12px;font-size:var(--text-body-sm);gap:6px}
.btn-lg{height:52px;padding:0 26px;font-size:var(--text-body);gap:10px}
.btn-secondary{background:var(--surface-card);color:var(--text-primary);border-color:var(--border-default);box-shadow:var(--shadow-xs)}
.btn-secondary:hover{background:var(--neutral-50);color:var(--text-primary)}
.btn-full{width:100%;display:flex}

.btn-sweep{
  background-image:none;background-size:100% 100%;
}
.btn-sweep:hover{
  background-image:linear-gradient(100deg,var(--camofi-blue) 0%,var(--camofi-blue-hover) 18%,var(--sand-400) 38%,var(--camofi-blue-hover) 50%,var(--camofi-blue) 62%,var(--sand-400) 82%,var(--camofi-blue-hover) 100%);
  background-size:360% 100%;
  animation:camofiButtonSweep 5.5s linear infinite;
}
@keyframes camofiButtonSweep{0%{background-position:0% 0}100%{background-position:300% 0}}
@media (prefers-reduced-motion:reduce){.btn-sweep:hover{animation:none}}

/* ---------- Badge ---------- */
.badge{
  display:inline-flex;align-items:center;gap:6px;height:22px;padding:0 9px;
  border-radius:var(--radius-pill);font-size:var(--text-micro);font-weight:var(--weight-semibold);
  letter-spacing:var(--tracking-label);text-transform:uppercase;white-space:nowrap;
  background:var(--blue-50);color:var(--camofi-blue);border:1px solid var(--blue-100);
}
.badge-lg{font-size:15px;height:32px;padding:0 16px;letter-spacing:-0.03em;text-transform:none;font-weight:700}

/* ---------- Icon ---------- */
.icon{display:inline-flex;flex:0 0 auto}
.icon svg{display:block}

/* ---------- Form fields ---------- */
.field{display:flex;flex-direction:column;gap:6px}
.field label{font-size:var(--text-caption);font-weight:var(--weight-medium);color:var(--text-secondary)}
.field-row{display:grid;grid-template-columns:1fr 1fr;gap:12px;width:100%}
.input, textarea.input{
  width:100%;height:40px;padding:0 14px;font-family:var(--font-sans);font-size:var(--text-body-sm);
  color:var(--text-primary);background:var(--surface-card);border:1px solid var(--border-default);
  border-radius:var(--radius-md);outline:none;box-shadow:var(--shadow-xs);transition:var(--transition-control);
}
.input:hover{border-color:var(--border-strong)}
.input:focus{border-color:var(--camofi-blue);box-shadow:var(--shadow-focus)}
.input::placeholder{color:var(--text-tertiary);transition:opacity var(--duration-fast) var(--ease-standard)}
.input:focus::placeholder{opacity:0.55}
textarea.input{height:auto;min-height:88px;padding:10px 12px;resize:vertical;font:inherit}

/* ---------- Glass panel ---------- */
.glass-panel{
  position:relative;padding:40px;border-radius:var(--radius-2xl);
  background:var(--glass-fill-strong);
  backdrop-filter:blur(var(--glass-blur)) saturate(1.4);-webkit-backdrop-filter:blur(var(--glass-blur)) saturate(1.4);
  border:1px solid var(--glass-border);box-shadow:var(--shadow-glass);overflow:hidden;
}

/* ---------- Cards ---------- */
.card{position:relative;background:var(--surface-card);border:1px solid var(--border-subtle);border-radius:var(--radius-lg);padding:24px;box-shadow:var(--shadow-sm)}

/* ---------- Section background photography ----------
   Per the Camofi design master: full-bleed photograph, then a veil that
   carries the copy. The photo is a layer, never a decoration — the veil
   is what guarantees text contrast, so never remove one without the other. */
.section-bg{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:center;
  /* Held back until decoded so the section never flashes a raw photo edge. */
  opacity:0;transition:opacity var(--duration-slow) var(--ease-entrance);
}
.section-bg.is-loaded{opacity:1}
@media (prefers-reduced-motion:reduce){.section-bg{transition:none}}

/* Any parallax layer is oversized so it can travel without exposing an edge.
   The JS clamps movement to 16% of the host height; 18% of headroom leaves a
   margin. Too little headroom is why the hero parallax appeared not to work. */
.section-bg[data-parallax]{inset:-18% 0;height:136%}

/* ---------- Hero ---------- */
/* Sits in exactly one viewport when it fits, grows when it would otherwise
   clip the form. 100svh (not vh) so mobile browser chrome doesn't cause a
   jump as the address bar collapses. Header is 68px; the notch needs ~64px. */
#hero{
  position:relative;overflow:hidden;background:var(--surface-page);
  min-height:100svh;
  display:flex;align-items:center;
  padding:calc(68px + 40px) 40px 72px;
}
/* Fallback wash behind the photo: if the image is slow or blocked, the hero
   still reads as brand rather than as an empty grey box. */
#hero::before{content:"";position:absolute;inset:0;background:var(--gradient-brand-sand)}
.hero-veil{
  position:absolute;inset:0;
  background:linear-gradient(100deg,rgba(255,255,255,0.97) 0%,rgba(255,255,255,0.9) 30%,rgba(255,255,255,0.52) 55%,rgba(255,255,255,0.16) 78%,rgba(255,255,255,0.02) 100%);
}
.hero-inner{position:relative;width:100%;max-width:var(--container-max);margin:0 auto;display:grid;grid-template-columns:1.05fr 0.95fr;gap:56px;align-items:center}
.hero-copy h1{font-size:clamp(42px,5vw,70px);line-height:1.03;letter-spacing:-0.03em;font-weight:600}
.hero-copy p{margin-top:22px;max-width:520px;font-size:var(--text-body-lg);line-height:1.55;color:var(--text-secondary)}
/* Eyebrow gets its own line so the four regulators always sit together as a
   set. They scale down rather than orphaning onto a second row. */
.reg-badges{display:flex;flex-direction:column;align-items:flex-start;gap:14px;margin-top:32px}
.reg-eyebrow{font-size:var(--text-micro);letter-spacing:var(--tracking-eyebrow);text-transform:uppercase;font-weight:600;color:var(--text-tertiary)}
.reg-pills{display:flex;flex-wrap:nowrap;align-items:center;gap:clamp(6px,0.9vw,10px)}
.reg-pill{
  display:inline-flex;align-items:center;flex:0 1 auto;min-width:0;
  gap:clamp(5px,0.7vw,9px);
  padding:9px clamp(10px,1.2vw,16px) 9px clamp(8px,1vw,12px);
  border-radius:940px;
  background:transparent;   /* no fill, no outline — flag and label only */
}
.reg-pill img{display:block;width:20px;height:14px;flex:0 0 auto;object-fit:cover;border-radius:2px;box-shadow:0 0 0 1px rgba(0,0,0,0.08)}
.reg-pill span{font-size:clamp(12px,1.15vw,15px);font-weight:700;letter-spacing:-0.03em;color:var(--camofi-blue);white-space:nowrap}

.hero-form h3{font-size:28px;font-weight:700;letter-spacing:-0.03em;margin:0 0 22px}
.hero-form-fields{display:flex;flex-direction:column;gap:14px}

/* ---------- Form confirmation ----------
   On success the panel itself becomes the message, then returns to the form.
   A line of text under the button was too easy to miss. */
.hero-form{position:relative}
.hero-form-fields{transition:opacity var(--duration-base) var(--ease-standard),transform var(--duration-base) var(--ease-standard)}
.hero-form.is-sent .hero-form-fields,
.hero-form.is-sent h3{opacity:0;transform:translateY(-6px);pointer-events:none}
.hero-form h3{transition:opacity var(--duration-base) var(--ease-standard),transform var(--duration-base) var(--ease-standard)}

.form-sent{
  position:absolute;inset:0;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:10px;padding:40px;text-align:center;
  opacity:0;visibility:hidden;transform:translateY(8px);
  transition:opacity var(--duration-slow) var(--ease-entrance),
             transform var(--duration-slow) var(--ease-entrance),
             visibility 0s linear var(--duration-slow);
}
.hero-form.is-sent .form-sent{opacity:1;visibility:visible;transform:none;transition-delay:120ms,120ms,0s}
.form-sent-icon{
  display:grid;place-items:center;width:52px;height:52px;margin-bottom:4px;
  border-radius:50%;background:var(--signal-positive-surface);color:var(--signal-positive);
}
.form-sent-title{font-size:var(--text-h4);font-weight:var(--weight-semibold);color:var(--text-primary)}
.form-sent-copy{font-size:var(--text-body-sm);color:var(--text-secondary);max-width:260px}
@media (prefers-reduced-motion:reduce){
  .hero-form-fields,.hero-form h3,.form-sent{transition:none}
}

/* ---------- Platform reach (logo marquee) ---------- */
#platform-reach{position:relative;padding:88px 40px;background:var(--gradient-brand-wash),var(--surface-page)}
/* 1040px matches .compare-heading in the security section. At 900px the line
   broke early and left "model." stranded on its own. */
#platform-reach h2{font-size:clamp(30px,3.4vw,44px);max-width:1040px;margin:0 auto;text-align:center;text-wrap:balance}
.logo-marquee-wrap{margin-top:64px;position:relative;overflow:hidden;mask-image:linear-gradient(90deg,transparent,black 8%,black 92%,transparent);-webkit-mask-image:linear-gradient(90deg,transparent,black 8%,black 92%,transparent)}
.logo-track{display:flex;gap:0;width:max-content;animation:camofi-logo-scroll 26s linear infinite}
@media (prefers-reduced-motion:reduce){.logo-track{animation:none}}
@keyframes camofi-logo-scroll{0%{transform:translateX(0)}100%{transform:translateX(-50%)}}
.logo-marquee-wrap:hover .logo-track{animation-play-state:paused}
.logo-set{display:flex;align-items:center;gap:clamp(56px,6vw,84px);flex-shrink:0;padding-right:clamp(56px,6vw,84px)}
.logo-set img{height:26px;width:auto;flex-shrink:0;opacity:0.72;transition:opacity var(--duration-base) var(--ease-standard)}
.logo-set img:hover{opacity:1}
.logo-set img.h-sm{height:22px}
.logo-set img.h-md{height:24px}

/* ---------- How it works ---------- */
#how-it-works{position:relative;padding:100px 40px 110px;background:transparent}
#how-it-works h2{margin-top:16px;font-size:clamp(30px,3.6vw,46px);max-width:75%}
#how-it-works > .container > p{margin-top:18px;max-width:640px;font-size:var(--text-body-lg);line-height:1.55;color:var(--text-secondary)}
.hiw-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:28px;margin-top:48px}
.hiw-card{min-width:0;border:1px solid var(--border-subtle);border-radius:var(--radius-lg);background:var(--surface-page);padding:28px;display:flex;flex-direction:column;gap:20px;transition:var(--transition-control)}
/* Deliberately no :hover — these cards are not clickable and a hover
   affordance on static content is a false promise. */
.hiw-visual{position:relative;height:190px;border-radius:var(--radius-lg);overflow:hidden;background:linear-gradient(160deg,var(--blue-50) 0%,var(--surface-page) 62%);border:1px solid var(--border-subtle);padding:16px;box-sizing:border-box}
.hiw-visual::before{content:"";position:absolute;inset:0;background:radial-gradient(90% 70% at 8% 0%,rgba(0,0,255,0.07) 0%,rgba(0,0,255,0) 70%)}
.hiw-visual > *{position:relative}
.hiw-icon{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:8px;background:var(--camofi-blue)}
.hiw-title-row{display:flex;align-items:center;gap:12px}
.hiw-title-row h4{font-size:22px;font-weight:700;letter-spacing:-0.03em}
.hiw-card p{margin-top:14px;font-size:var(--text-body-sm);line-height:1.55;color:var(--text-secondary)}

/* small mock-UI bits used inside the how-it-works cards */
.mock-panel{background:var(--surface-card);border:1px solid var(--border-subtle);border-radius:var(--radius-lg);box-shadow:var(--shadow-md);padding:12px}
.mock-line{font-size:13px;line-height:1.45;color:var(--text-primary)}
.mock-chip{display:inline-flex;align-items:center;gap:6px;min-width:0;max-width:100%;height:26px;padding:0 9px;border-radius:var(--radius-sm);background:var(--surface-sunken);border:1px solid var(--border-subtle);font-size:11px;color:var(--text-secondary);white-space:nowrap}
.mock-chip span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mock-toolbar{display:flex;align-items:center;gap:6px;margin-top:12px}
.mock-pill{display:inline-flex;align-items:center;height:28px;padding:0 11px;border-radius:var(--radius-pill);background:var(--surface-card);border:1px solid var(--border-default);font-size:11px;white-space:nowrap}
.mock-pill-brand{background:var(--camofi-blue);color:#fff;height:30px;gap:5px;flex-shrink:0}
.mock-select-row{display:flex;align-items:center;gap:6px;height:28px;padding:0 11px;border-radius:var(--radius-pill);background:var(--blue-50);border:1px solid var(--blue-200);font-size:11px}
.mock-menu{margin-top:8px;padding:5px;background:var(--surface-card);border:1px solid var(--border-subtle);border-radius:var(--radius-lg);box-shadow:var(--shadow-lg)}
.mock-menu-row{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:7px 9px;border-radius:var(--radius-md);background:transparent}
.mock-menu-row.active{background:var(--blue-50)}
.mock-menu-row span:first-child{font-size:12px;font-weight:500;white-space:nowrap;color:var(--text-primary)}
.mock-menu-row.active span:first-child{color:var(--camofi-blue)}
.mock-menu-row span:last-child{font-size:11px;color:var(--text-tertiary);white-space:nowrap;font-variant-numeric:tabular-nums}
.mock-status{display:inline-flex;align-items:center;gap:5px;height:20px;padding:0 8px;border-radius:var(--radius-pill);background:rgba(15,122,90,0.1);color:#0F7A5A;font-size:10px;font-weight:600;letter-spacing:0.06em;text-transform:uppercase;white-space:nowrap}
.mock-status.caution{background:rgba(154,107,0,0.12);color:#9A6B00}
.mock-status .dot{width:5px;height:5px;border-radius:50%;background:currentColor}
.mock-meta{font-size:10px;color:var(--text-tertiary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mock-heading{margin-top:8px;font-size:13px;font-weight:600;letter-spacing:-0.02em;line-height:1.25}
.mock-sub{margin-top:5px;font-size:11px;line-height:1.45;color:var(--text-secondary)}
.mock-stat-grid{display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-top:9px}
.mock-stat{padding:8px 10px;border:1px solid var(--border-subtle);border-radius:var(--radius-md);min-width:0}
.mock-stat-label{font-size:10px;color:var(--text-tertiary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mock-stat-value{margin-top:2px;font-size:12px;font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap}

/* ---------- Security guarantee (dark) ---------- */
#security-guarantee{position:relative;overflow:hidden;padding:120px 40px;background:#05050A;color:#fff;text-align:center}
/* Prism facets over near-black — a texture, not an image.
   Opacity is what makes the parallax on this section readable or not. It ran at
   14% and could not be seen moving: there was ~237px of travel across a full
   pass, but you cannot perceive motion in something you can barely perceive.
   Raising the speed alone would not have fixed that. 22% keeps it a texture
   while giving the movement something to register against. Dial this, not the
   speed, if the effect needs to be stronger or weaker. */
#security-guarantee .prism-bg{will-change:transform}
#security-guarantee .prism-bg.is-loaded{opacity:0.22}
.security-veil{position:absolute;inset:0;background:radial-gradient(70% 60% at 50% 40%,rgba(5,5,10,0.35) 0%,rgba(5,5,10,0.82) 100%)}
.security-inner{position:relative;max-width:760px;margin:0 auto}
.security-inner h2{color:#fff;font-size:clamp(32px,3.8vw,48px)}
.security-inner > p{margin-top:20px;font-size:var(--text-body-lg);line-height:1.6;color:rgba(255,255,255,0.72)}
.security-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:32px;margin-top:52px;text-align:left}
.security-grid h4{margin-top:14px;color:#fff;font-size:var(--text-h4)}
.security-grid p{margin-top:8px;font-size:var(--text-body-sm);line-height:1.6;color:rgba(255,255,255,0.6)}
.security-cta{margin-top:52px}
.compare-wrap{position:relative;max-width:1144px;margin:96px auto 0;display:flex;flex-direction:column;align-items:center;gap:34px}
.compare-heading{max-width:1040px;color:#fff;font-size:clamp(24px,2.6vw,34px);font-weight:700;line-height:1.25;letter-spacing:-0.01em;text-align:center}
.compare-cards{display:flex;flex-direction:row;gap:24px;justify-content:center;align-items:flex-start;flex-wrap:wrap;text-align:left}
.compare-card{flex:1 1 480px;max-width:560px;border-radius:16px;background:rgba(255,255,255,0.04);box-shadow:inset 0 0 0 1px rgba(255,255,255,0.12);padding:26px;display:flex;flex-direction:column;gap:12px}
/* Not clickable — no hover state. */
.compare-card .compare-title{color:#fff;font-size:20px;font-weight:600;line-height:1.18}
.compare-card .compare-copy{font-size:15px;font-weight:400;line-height:1.45;color:rgba(255,255,255,0.62)}

/* ---------- Key features / stepper ---------- */
/* Dune photography per the design master. The sand gradient this replaces was
   a stand-in for the photo, which is why its ramp was named "sand". */
#key-features{position:relative;overflow:hidden;padding:96px 40px 104px;background:var(--surface-page)}
#key-features::before{content:"";position:absolute;inset:0;background:linear-gradient(160deg,var(--sand-100) 0%,var(--surface-page) 55%)}
.kf-veil{
  position:absolute;inset:0;z-index:0;
  background:linear-gradient(100deg,rgba(255,255,255,0.88) 0%,rgba(255,255,255,0.74) 34%,rgba(255,255,255,0.42) 62%,rgba(255,255,255,0.24) 100%);
}
/* The veil is positioned, so it paints above any STATIC content — which hid
   the pill, headline and subheadline while the stepper (.kf-grid is
   position:relative) stayed visible. Lift the whole column above it.
   Any section with a .section-bg + veil needs its content positioned. */
#key-features > .container{position:relative;z-index:1}
.kf-intro{max-width:680px}
.kf-intro h2{margin-top:16px;font-size:clamp(30px,3.4vw,44px);line-height:1.1}
.kf-intro p{margin-top:16px;font-size:var(--text-body-lg);line-height:1.55;color:var(--text-secondary)}
.kf-grid{position:relative;margin-top:48px;display:grid;grid-template-columns:repeat(auto-fit,minmax(340px,1fr));gap:48px;align-items:start}
.kf-steps{position:relative;display:flex;flex-direction:column;gap:4px}
.kf-steps::before{content:"";position:absolute;left:19px;top:34px;bottom:34px;width:1px;background:var(--border-strong)}
.kf-step{display:flex;align-items:flex-start;gap:18px;width:100%;text-align:left;padding:18px 20px;margin-left:-20px;border-radius:var(--radius-lg);background:transparent;border:none;cursor:pointer;font-family:var(--font-sans);color:var(--text-secondary);transition:var(--transition-control)}
.kf-step:hover:not(.active){background:rgba(0,0,255,0.035);color:var(--text-primary)}
.kf-step:hover:not(.active) .kf-step-num{box-shadow:inset 0 0 0 1px var(--blue-300);color:var(--camofi-blue)}
.kf-step.active{color:var(--text-primary);background:rgba(0,0,255,0.04)}
.kf-step-num{position:relative;flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;border-radius:50%;font-size:14px;font-weight:600;font-variant-numeric:tabular-nums;background:var(--surface-card);color:var(--text-tertiary);box-shadow:inset 0 0 0 1px var(--border-default);transition:var(--transition-control)}
.kf-step.active .kf-step-num{background:var(--camofi-blue);color:#fff;box-shadow:none}
.kf-step-body{display:flex;flex-direction:column;gap:5px;min-width:0}
.kf-step-title{font-size:19px;font-weight:600;letter-spacing:-0.02em}
.kf-step-copy{font-size:var(--text-body-sm);line-height:1.55;max-width:420px;color:var(--text-secondary);transition:var(--transition-control)}
/* Drawer affordance. Desktop is a tablist, where a chevron would be a lie. */
.kf-chevron{display:none;flex:0 0 auto;margin-left:auto;color:var(--camofi-blue);transition:transform var(--duration-drawer) var(--ease-standard)}
/* display:none cannot be transitioned, so the drawer wrapper animates its grid
   row from 0fr to 1fr instead. That is what gives a real height animation
   without hard-coding a max-height that would have to guess each panel's size
   and would make the easing lie on the short ones. */
.kf-drawer{display:grid;grid-template-rows:minmax(0,1fr)}
.kf-panel-wrap{min-width:0}
.kf-panel{padding:24px;border:1px solid var(--border-subtle);border-radius:var(--radius-lg);background:var(--surface-card);box-shadow:var(--shadow-sm)}
.kf-panel[hidden]{display:none}
.kf-notice{display:flex;align-items:center;gap:10px;margin-top:16px;padding:12px 16px;border-radius:var(--radius-lg);background:var(--blue-50);border:1px solid var(--blue-100)}
.kf-notice span{font-size:14px;font-weight:600;letter-spacing:-0.02em;color:var(--camofi-blue)}
.kf-cta{margin-top:52px}

/* ---------- Footer ---------- */
.site-footer{background:var(--surface-card);border-top:1px solid var(--border-subtle);padding:56px 40px 32px}
.site-footer .logo img{height:22px;width:auto}
.site-footer .tagline{margin-top:16px;font-size:var(--text-caption);color:var(--text-tertiary);line-height:1.6;max-width:230px}
.footer-bottom{max-width:var(--container-max);margin:36px auto 0;padding-top:20px;border-top:1px solid var(--border-subtle);display:flex;justify-content:space-between;font-size:var(--text-caption);color:var(--text-tertiary)}
.footer-bottom .footer-links{display:flex;gap:20px}
.footer-bottom a{color:inherit;text-decoration:none;transition:color var(--duration-fast) var(--ease-standard)}
.footer-bottom a:hover{color:var(--text-primary);text-decoration:underline;text-underline-offset:4px;text-decoration-thickness:1px}

/* =========================================================================
   INTERACTION LAYER
   Reference: Mercury, dialled back ~40%. Full rationale in INTERACTION.md.
   Rules: motion serves comprehension, never decoration. Nothing blocks
   reading. Every animated property is opacity or transform only.
   ========================================================================= */

/* ---------- Icon system (self-hosted sprite) ---------- */
.sprite{position:absolute;width:0;height:0;overflow:hidden}
.ico{
  display:block;flex:0 0 auto;width:16px;height:16px;
  fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round;
}
.ico-13{width:13px;height:13px;stroke-width:2}
.ico-17{width:17px;height:17px}
.ico-18{width:18px;height:18px}
.ico-20{width:20px;height:20px}
.ico-22{width:22px;height:22px}
.icon-brand{color:var(--camofi-blue)}
.icon-muted{color:var(--text-tertiary)}
.hiw-icon,.security-grid .icon,.mock-pill-brand .icon{color:#fff}

/* ---------- Skip link ---------- */
.skip-link{
  position:absolute;left:16px;top:-64px;z-index:100;
  display:inline-flex;align-items:center;height:40px;padding:0 18px;
  border-radius:var(--radius-pill);background:var(--camofi-blue);color:#fff;
  font-size:var(--text-body-sm);font-weight:var(--weight-medium);text-decoration:none;
  transition:top var(--duration-base) var(--ease-entrance);
}
.skip-link:focus{top:14px;color:#fff;text-decoration:none}

/* ---------- Button internals ---------- */
.btn-label{display:inline-block}
/* The arrow leans forward on hover — 2px, the smallest movement that still reads. */
.btn .icon{transition:transform var(--duration-base) var(--ease-standard)}
.btn:hover .icon{transform:translateX(2px)}
.btn[disabled]{opacity:0.72;cursor:default}
.btn[disabled]:hover .icon{transform:none}

/* ---------- Form status ---------- */
.form-status{
  margin:0;font-size:var(--text-caption);line-height:1.5;color:var(--signal-positive);
  max-height:0;opacity:0;overflow:hidden;
  transition:max-height var(--duration-base) var(--ease-standard),opacity var(--duration-base) var(--ease-standard);
}
.form-status.is-visible{max-height:80px;opacity:1;margin-top:2px}
.form-status.is-error{color:var(--signal-critical)}

/* Honeypot. Visually and programmatically gone; bots still fill it. */
.hp-field{position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden}

/* ---------- Card hover (slower than a control: it's a surface, not a button) ---------- */


/* ---------- Key-features panel helpers ---------- */
.kf-panel-label{margin-top:14px;font-size:var(--text-micro);letter-spacing:var(--tracking-eyebrow);text-transform:uppercase;font-weight:600;color:var(--text-tertiary)}
.kf-row{padding:10px 0;border-top:1px solid var(--border-subtle)}
.kf-panel-foot{margin-top:12px;padding-top:12px;border-top:1px solid var(--border-subtle);font-size:11px;color:var(--text-tertiary);line-height:1.5}
/* Panel content cross-fades on stage change so the switch reads as one object updating. */
.kf-panel{animation:kfPanelIn 640ms var(--ease-entrance) both}
@keyframes kfPanelIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.kf-panel{animation:none}}


/* ---------- Active stage: force field ----------
   A slow ring pushing outward from the selected number. Reads as "this is a
   live control" without turning the stepper into a toy. */
.kf-step-num::after{
  content:"";position:absolute;inset:-4px;border-radius:50%;
  border:1.5px solid var(--camofi-blue);
  opacity:0;transform:scale(0.9);pointer-events:none;
}
.kf-step.active .kf-step-num::after{animation:kfForceField 1.5s var(--ease-standard) infinite}
@keyframes kfForceField{
  0%{opacity:0.55;transform:scale(0.92)}
  70%{opacity:0;transform:scale(1.45)}
  100%{opacity:0;transform:scale(1.45)}
}
.kf-step:hover:not(.active) .kf-step-num::after{opacity:0.25;transform:scale(1.06);transition:opacity var(--duration-fast),transform var(--duration-fast)}
@media (prefers-reduced-motion:reduce){.kf-step.active .kf-step-num::after{animation:none;opacity:0.4;transform:scale(1.06)}}

/* ---------- Drifting sand ----------
   A very slow, very small pan on the dune. Enough to stop the section
   feeling like a flat photograph; too small to notice as motion. */
/* The dune photograph is STILL. The motion is a particle layer drawn over it
   — grains of sand carried on the wind — not the image itself panning.
   Panning the whole photo was the wrong effect entirely. */
.sand-layer{
  position:absolute;inset:0;z-index:0;
  width:100%;height:100%;
  pointer-events:none;
  /* Sand blows across the open dune, not across the copy. The mask keeps the
     left column clean — grains over body text read as dirt, not weather. */
  -webkit-mask-image:linear-gradient(100deg,transparent 0%,transparent 22%,rgba(0,0,0,0.35) 42%,#000 68%);
  mask-image:linear-gradient(100deg,transparent 0%,transparent 22%,rgba(0,0,0,0.35) 42%,#000 68%);
}


/* ---------- Scroll reveal ----------
   Applied only when JS is present, so the page is fully readable if the
   script fails, is blocked, or the crawler never runs it. */
html.js [data-reveal]{
  opacity:0;
  transform:translateY(var(--reveal-distance));
  transition:opacity var(--reveal-duration) var(--ease-entrance),transform var(--reveal-duration) var(--ease-entrance);
  transition-delay:var(--reveal-delay,0ms);
  /* No will-change here. It was promoting every revealable element to its
     own compositor layer — 27 layers at once, on a page that also runs
     backdrop-filter and two full-bleed transformed photographs. That
     saturates the compositor and stalls the renderer, which stops
     transitions progressing at all. The browser handles a plain
     opacity/transform transition perfectly well without the hint. */
}
html.js [data-reveal].is-revealed{opacity:1;transform:none}

@media (prefers-reduced-motion:reduce){
  html.js [data-reveal]{opacity:1;transform:none;transition:none}
}

/* ---------- Responsive ---------- */
@media (max-width:980px){
  .hero-inner{grid-template-columns:1fr;gap:40px}
  /* Copy leads, form follows. Landing on six blank fields with no context
     is a conversion problem. Set .hero-form{order:-1} to reverse. */
  .hero-copy{order:-1}
  .security-grid{grid-template-columns:1fr}
  .compare-cards{flex-direction:column;align-items:stretch}
  /* flex-basis follows the MAIN axis. The row layout reads `flex:1 1 480px` as
     a width; the moment the container turns column it reads the same 480px as a
     HEIGHT, and both cards inflate to 480px tall regardless of their copy.
     Reset the basis when the axis flips. */
  .compare-card{flex:0 0 auto;width:100%;max-width:none}
}

@media (max-width:860px){
  .nav-toggle{display:inline-flex}
  /* Below this width the hero form is far enough down the page that the
     header CTA is a genuine shortcut, so it is always available. */
  .header-cta{opacity:1;visibility:visible;transform:none}

  .site-nav{
    position:absolute;top:100%;left:0;right:0;
    flex-direction:column;gap:0;
    padding:8px 20px 16px;
    /* Solid, not glass. A translucent panel let the hero headline read
       straight through the menu items. */
    background:var(--surface-card);
    border-bottom:1px solid var(--border-default);
    box-shadow:var(--shadow-lg);
    opacity:0;visibility:hidden;transform:translateY(-8px);
    transition:opacity var(--duration-base) var(--ease-standard),
               transform var(--duration-base) var(--ease-standard),
               visibility 0s linear var(--duration-base);
  }
  .site-header.nav-open .site-nav{
    opacity:1;visibility:visible;transform:none;transition-delay:0s,0s,0s;
  }
  .site-nav a{padding:14px 0;font-size:var(--text-body);border-bottom:1px solid var(--border-subtle)}
  .site-nav a:last-child{border-bottom:none}
  .site-nav a::after{display:none}
}

/* 340px min column x2 + 48px gap + 80px section padding = 808px. Below that the
   auto-fit grid drops to one column and the panel lands underneath all four
   steps — tapping a step then changes a picture most of a screen away, which
   reads as broken rather than as a response. The steps carry the meaning on
   their own, so the panel comes out at exactly the width it stops working.
   Deriving the number keeps it honest: change the 340px or the gap above and
   this has to move with them. */
@media (max-width:808px){
  /* One column, and each stage's panel sits directly under its own copy:
     step 1, panel 1, step 2, panel 2. display:contents dissolves the two
     wrapper boxes so all eight children become grid items of .kf-grid, which
     is what makes them orderable against each other — nth-child still counts
     within the original parent, so the pairing stays correct.
     The connector line has to go explicitly. .kf-steps::before is absolutely
     positioned against .kf-steps, and once that box is gone the line resolves
     against .kf-grid instead and runs the full height of the section, showing
     as stray stubs in the gaps between panels. It belongs to the desktop rail
     of steps, and there is no rail here. */
  .kf-steps,.kf-panel-wrap{display:contents}
  .kf-steps::before{display:none}
  .kf-grid{grid-template-columns:1fr;gap:0;margin-top:36px}
  .kf-step:nth-child(1){order:0}  .kf-drawer:nth-child(1){order:1}
  .kf-step:nth-child(2){order:2}  .kf-drawer:nth-child(2){order:3}
  .kf-step:nth-child(3){order:4}  .kf-drawer:nth-child(3){order:5}
  .kf-step:nth-child(4){order:6}  .kf-drawer:nth-child(4){order:7}
  .kf-panel{margin:2px 0 12px;padding:16px}
  .kf-step-copy{max-width:none}

  /* The drawer. It has to be minmax(0,0fr), not a bare 0fr: a flexible track
     carries an automatic minimum of its item's min-content contribution, and
     the panel's 24px padding plus border is part of that. Measured — bare 0fr
     leaves a 49px stub of empty card under every closed row; minmax(0,0fr)
     reaches a true zero. min-height:0 on the child is not enough on its own,
     because padding sits outside the content box it constrains. */
  .kf-drawer{grid-template-rows:minmax(0,0fr);overflow:hidden;transition:grid-template-rows var(--duration-drawer) var(--ease-standard)}
  .kf-drawer.is-open{grid-template-rows:minmax(0,1fr)}
  .kf-drawer > .kf-panel{overflow:hidden;min-height:0}

  /* Accordion. Collapsed shows the number and the stage name only; the
     description and the panel are both inside the drawer. main.js drives the
     open state through aria-expanded, so the attribute is the single source of
     truth for both semantics and styling — there is no separate class to fall
     out of sync with it. */
  .kf-chevron{display:inline-flex;align-self:center}
  /* Negative margins on both sides, mirroring, so the row's padding does not
     inset the copy relative to the panel below it. Without the right one the
     paragraph stopped 20px short of the panel edge. */
  .kf-step{align-items:center;margin-left:-20px;margin-right:-20px;padding:14px 20px}
  /* Collapsed is a single line, so centring the number against the title is
     right. Open, the body grows and the number belongs at the top of it. */
  .kf-step[aria-expanded="true"]{align-items:flex-start;padding-bottom:6px}
  /* Same 0fr trick as the drawer — the description slides rather than snapping.
     The gap goes to 0 and becomes padding inside the clipped child, or it would
     hold a 5px space open while collapsed. */
  .kf-step-body{display:grid;grid-template-rows:auto minmax(0,0fr);gap:0;transition:grid-template-rows var(--duration-drawer) var(--ease-standard)}
  .kf-step[aria-expanded="true"] .kf-step-body{grid-template-rows:auto minmax(0,1fr)}
  .kf-step-copy{display:block;overflow:hidden;min-height:0;margin-top:0;padding-top:6px}
  .kf-step[aria-expanded="true"] .kf-chevron{transform:rotate(180deg)}
  .kf-step[aria-expanded="true"] .kf-step-title{color:var(--text-primary)}
  /* Rows are the hit target now, so they need a visible boundary. Steps are
     still DOM siblings inside .kf-steps even though display:contents reorders
     them visually, so adjacency matches rows 2-4 as intended. (A .kf-panel +
     .kf-step rule would never fire — those live in different parents.) */
  .kf-step + .kf-step{border-top:1px solid var(--border-subtle)}
  .kf-step.active{background:transparent}
  .kf-step.active .kf-step-num::after{animation:none;opacity:0}
}

@media (max-width:760px){
  .site-header{gap:16px;padding:0 20px}

  /* Vertical rhythm. Only the horizontal padding was being reduced for mobile,
     so every section kept its full desktop height — the marquee and the
     Solution heading were 188px apart on a 400px-wide screen. */
  #platform-reach{padding-top:56px;padding-bottom:48px}
  .logo-marquee-wrap{margin-top:36px}
  #how-it-works{padding-top:56px;padding-bottom:64px}
  #security-guarantee{padding-top:72px;padding-bottom:72px}
  .compare-wrap{margin-top:56px;gap:24px}
  #key-features{padding-top:64px;padding-bottom:72px}

  /* Security section centres on mobile. The three-column grid reads as columns
     of left-aligned text on desktop; stacked on a phone that left edge has
     nothing to align against, so the section is centred to match the heading
     and copy directly above it. */
  .security-grid,.compare-cards,.compare-card{text-align:center}
  .security-grid > div{display:flex;flex-direction:column;align-items:center}
  .compare-card{align-items:center}
  #hero{padding:calc(68px + 28px) 20px 64px;min-height:100svh}
  .container,#hero,#platform-reach,#how-it-works,#security-guarantee,#key-features,.site-footer{padding-left:20px;padding-right:20px}
  #how-it-works h2{max-width:100%}
  .field-row{grid-template-columns:1fr}
  .footer-bottom{flex-direction:column;gap:12px;align-items:flex-start}
  /* .kf-step geometry is set once in the 808px accordion block above. A second
     override here would win on the cascade and silently undo the edge alignment
     the accordion depends on. */
  .glass-panel{padding:24px}
}

/* Touch devices have no hover — never leave a state stuck after a tap. */
@media (hover:none){
  .btn:hover .icon{transform:none}
  .site-nav a:hover::after{transform:scaleX(0)}
  .kf-step:hover:not(.active){background:transparent}
}
