  :root{
    --paper:#ffffff;
    --paper-2:#f6f8f7;
    --paper-3:#edf1ef;
    --ink:#0c1210;
    --ink-2:#454f4a;
    --ink-3:#6d7873;
    --ink-4:#98a19c;
    --green:#0a5c3c;
    --green-hi:#0e7a4f;
    --green-soft:#e9f3ee;
    --green-line:#c5ddd1;
    --rule:#e4e9e6;
    --rule-2:#d3dbd7;
    --ink-contrast:#ffffff;
    --nav-bg:rgba(255,255,255,.86);
    --mega-bg:#ffffff;
    --nav-hover:rgba(12,18,16,.05);
    --grain-blend:multiply;
    --grain-opacity:.16;
    --shadow:0 1px 2px rgba(12,18,16,.04),0 12px 32px -12px rgba(12,18,16,.10);
    --r:8px;
  }

  *{margin:0;padding:0;box-sizing:border-box}
  html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}

  body{
    background:var(--paper);
    color:var(--ink);
    font-family:"Instrument Sans",-apple-system,Helvetica,Arial,sans-serif;
    font-size:17px;
    line-height:1.6;
    -webkit-font-smoothing:antialiased;
    -moz-osx-font-smoothing:grayscale;
    font-feature-settings:"kern" 1,"liga" 1,"cv11" 1;
  }

  /* very light tooth so surfaces aren't machine-flat */
  body::after{
    content:"";position:fixed;inset:0;pointer-events:none;z-index:9999;
    opacity:var(--grain-opacity);mix-blend-mode:var(--grain-blend);
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='.4'/%3E%3C/svg%3E");
  }

  h1,h2,h3{font-weight:600;letter-spacing:-.032em;line-height:1.04}
  h1{letter-spacing:-.042em}

  a{color:var(--green);text-decoration:none}
  ::selection{background:var(--green);color:#fff}
  :focus-visible{outline:2px solid var(--green);outline-offset:3px;border-radius:2px}

  /* mono is reserved for labels, stages and figures — never prose */
  .mono{
    font-family:"IBM Plex Mono",ui-monospace,monospace;
    font-size:.7rem;letter-spacing:.11em;text-transform:uppercase;font-weight:500;
    color:var(--ink-3);
  }
  .tnum{font-variant-numeric:tabular-nums}

  /* ---------- ribbon ---------- */

  /* ---------- nav ---------- */
  nav{
    position:sticky;top:0;z-index:60;background:var(--nav-bg);
    backdrop-filter:saturate(180%) blur(14px);
    border-bottom:1px solid var(--rule);
    display:flex;align-items:center;justify-content:space-between;
    gap:2rem;padding:.95rem 2.2rem;
  }
  .logo{font-weight:700;font-size:1.22rem;letter-spacing:-.03em;color:var(--ink);white-space:nowrap;line-height:1.1}
  .logo span:first-of-type{color:var(--green)}
  .logo .tag{
    display:block;font-family:"IBM Plex Mono",monospace;font-size:.58rem;
    letter-spacing:.14em;text-transform:uppercase;color:var(--ink-4);
    font-weight:400;margin-top:.2rem;
  }
  .nav-links{display:flex;align-items:center;gap:1.75rem;flex-wrap:wrap}
  .nav-links>a{font-size:.9rem;font-weight:500;color:var(--ink-2);transition:color .16s}
  .nav-links>a:hover{color:var(--ink)}
  .nav-login{
    border:1px solid var(--rule-2);padding:.5rem 1rem;border-radius:var(--r);
    color:var(--ink)!important;transition:border-color .16s,background .16s;
  }
  .nav-login:hover{border-color:var(--ink-3);background:var(--paper-2)}
  .nav-cta{
    background:var(--ink);color:#fff!important;padding:.55rem 1.1rem;
    border-radius:var(--r);transition:background .16s;
  }
  .nav-cta:hover{background:var(--green)}

  /* ---------- layout ---------- */
  section,footer{padding:5.5rem 2.2rem}
  .wrap{max-width:74rem;margin:0 auto}
  /* .alt used to be background:var(--paper-2) plus hairline rules. paper and
     paper-2 differ by about 5/255, so the stripe was invisible and the only
     thing separating sections was a 1px line: the page read as a document
     with rules rather than a product page with chapters. Grounds do that job
     now, and .alt is kept only so existing markup keeps working. */
  .alt{background:transparent}

  .sec-head{max-width:40rem;margin-bottom:2.6rem}
  .sec-head .mono{display:block;margin-bottom:1.3rem}
  .sec-head h2{font-size:clamp(2.1rem,4.4vw,3.3rem);margin-bottom:1.1rem}
  .sec-head h2 span{color:var(--green)}
  .sec-head p{color:var(--ink-2);font-size:1.05rem;max-width:38rem}

  /* ---------- buttons ---------- */
  .btn{
    display:inline-flex;align-items:center;justify-content:center;
    padding:.82rem 1.5rem;border-radius:var(--r);border:1px solid transparent;
    font-family:inherit;font-size:.95rem;font-weight:600;letter-spacing:-.01em;
    cursor:pointer;transition:background .16s,border-color .16s,color .16s;
  }
  .btn-primary{background:var(--ink);color:#fff}
  .btn-primary:hover{background:var(--green)}
  .btn-ghost{background:transparent;color:var(--ink);border-color:var(--rule-2)}
  .btn-ghost:hover{border-color:var(--ink);background:var(--paper-2)}

  /* ---------- hero ---------- */
  header.hero{ position:relative; padding:0 }
  .hero__inner{
    max-width:74rem;margin:0 auto;padding:9rem 2.2rem 6rem;
    display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.92fr);
    gap:4rem;align-items:center;
  }
  .hero .mono{display:flex;align-items:center;gap:.75rem;margin-bottom:1.7rem}
  .hero .mono::before{content:"";width:1.9rem;height:1px;background:var(--green)}
  h1{font-size:clamp(2.7rem,6.2vw,4.5rem);margin-bottom:1.6rem}
  h1 span{color:var(--green)}
  .lede{font-size:1.1rem;color:var(--ink-2);max-width:33rem;margin-bottom:2.2rem}
  .lede b{color:var(--ink);font-weight:600}
  .cta-row{display:flex;gap:.75rem;flex-wrap:wrap;margin-bottom:1.5rem}
  .micro{font-size:.82rem;color:var(--ink-3)}

  /* ---------- trust strip ---------- */
  .trust{background:transparent}
  .trust .wrap{
    display:flex;align-items:center;justify-content:space-between;gap:2rem;
    flex-wrap:wrap;padding:1.5rem 0;
  }
  .trust-label{
    font-family:"IBM Plex Mono",monospace;font-size:.63rem;letter-spacing:.13em;
    text-transform:uppercase;color:var(--ink-4);flex-shrink:0;
  }
  .trust-items{display:flex;align-items:center;gap:2.4rem;flex-wrap:wrap}
  .trust-item{display:flex;align-items:center;gap:.55rem;font-size:.87rem;font-weight:500;color:var(--ink-2)}
  .trust-item svg{width:1.05rem;height:1.05rem;flex-shrink:0;stroke:var(--green);fill:none;stroke-width:1.7}

  /* ---------- infrastructure ---------- */
  .infra{display:grid;grid-template-columns:repeat(3,1fr);gap:1.1rem;margin-bottom:1.1rem}
  .infra-card{border:1px solid var(--rule-2);border-radius:12px;padding:1.7rem;background:var(--paper)}
  .infra-card svg{width:1.4rem;height:1.4rem;stroke:var(--green);fill:none;stroke-width:1.6;margin-bottom:1rem}
  .infra-card h3{font-size:1.05rem;margin-bottom:.5rem}
  .infra-card p{font-size:.9rem;color:var(--ink-2)}
  .infra-strip{
    border:1px solid var(--rule-2);border-radius:12px;background:var(--paper);
    display:grid;grid-template-columns:repeat(4,1fr);
  }
  .infra-fig{padding:1.5rem 1.4rem;border-right:1px solid var(--rule)}
  .infra-fig:last-child{border-right:0}
  .infra-fig b{
    display:block;font-size:1.75rem;font-weight:600;letter-spacing:-.04em;
    font-variant-numeric:tabular-nums;margin-bottom:.25rem;
  }
  .infra-fig span{
    font-family:"IBM Plex Mono",monospace;font-size:.62rem;letter-spacing:.11em;
    text-transform:uppercase;color:var(--ink-3);
  }

  /* hero product shot — a real slice of the dashboard, not abstract claims */
  .shot{
    border:1px solid var(--rule-2);border-radius:12px;overflow:hidden;
    background:var(--paper);box-shadow:var(--shadow);
  }
  .shot-bar{
    display:flex;align-items:center;gap:.45rem;padding:.7rem .9rem;
    border-bottom:1px solid var(--rule);background:var(--paper-2);
  }
  .shot-bar i{width:9px;height:9px;border-radius:50%;background:var(--rule-2);display:block}
  .shot-url{
    margin-left:.5rem;font-family:"IBM Plex Mono",monospace;font-size:.66rem;
    color:var(--ink-3);background:var(--paper);border:1px solid var(--rule);
    border-radius:5px;padding:.2rem .6rem;
  }
  .shot-body{display:grid;grid-template-columns:7.2rem 1fr}
  .shot-side{border-right:1px solid var(--rule);padding:.9rem .7rem;background:var(--paper-2)}
  .shot-side b{
    display:block;font-size:.7rem;font-weight:700;letter-spacing:-.02em;margin-bottom:.7rem;padding-left:.3rem;
  }
  .shot-side b em{color:var(--green);font-style:normal}
  .shot-side u{
    display:block;text-decoration:none;font-size:.66rem;color:var(--ink-3);
    padding:.32rem .4rem;border-radius:5px;margin-bottom:.1rem;
  }
  .shot-side u.on{background:var(--green-soft);color:var(--green);font-weight:600}
  .shot-main{padding:1rem}
  .shot-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:.5rem;margin-bottom:.9rem}
  .shot-stat{border:1px solid var(--rule);border-radius:6px;padding:.55rem .6rem}
  .shot-stat span{display:block;font-family:"IBM Plex Mono",monospace;font-size:.52rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-4);margin-bottom:.2rem}
  .shot-stat b{font-size:.95rem;font-weight:700;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
  .shot-chart{display:flex;align-items:flex-end;gap:3px;height:3.6rem;padding-top:.3rem}
  .shot-chart i{flex:1;background:var(--green);border-radius:2px 2px 0 0;display:block;opacity:.28}
  .shot-chart i.hi{opacity:1}
  .shot-foot{
    display:flex;align-items:center;gap:.45rem;border-top:1px solid var(--rule);
    padding:.6rem .9rem;font-family:"IBM Plex Mono",monospace;font-size:.6rem;
    letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3);
  }
  .dot{width:6px;height:6px;border-radius:50%;background:var(--green);display:block;box-shadow:0 0 0 3px var(--green-soft)}

  /* ---------- plans ---------- */
  .plans{display:grid;grid-template-columns:repeat(3,1fr);gap:1.1rem}
  /* Four tiers do not fit the three-column rhythm, and squeezing them in
     makes every card too narrow to read a feature list in. Slightly
     tighter gap and padding buys the fourth column back. */
  .plans--4{grid-template-columns:repeat(4,1fr);gap:.85rem}
  .plans--4 .plan{padding:1.7rem 1.25rem}
  .plans--4 .plan .price{font-size:2.1rem}
  /* A feature a plan deliberately does NOT include. Saying so on the
     cheapest tier is worth more than leaving it out and letting someone
     buy the wrong thing and ask for a refund. */
  .plan li.not{color:var(--ink-3);text-decoration:none}
  .plan li.not::marker{color:var(--ink-4)}
  .plan{
    border:1px solid var(--rule-2);border-radius:12px;padding:2rem 1.7rem;
    display:flex;flex-direction:column;background:var(--paper);
  }
  .plan.featured{border-color:var(--green);box-shadow:var(--shadow);position:relative}
  .plan.featured::before{
    content:"Most popular";position:absolute;top:-.65rem;left:1.7rem;
    background:var(--green);color:#fff;font-family:"IBM Plex Mono",monospace;
    font-size:.58rem;letter-spacing:.1em;text-transform:uppercase;
    padding:.22rem .6rem;border-radius:4px;
  }
  .plan .name{
    font-family:"IBM Plex Mono",monospace;font-size:.68rem;letter-spacing:.12em;
    text-transform:uppercase;color:var(--ink-3);display:block;margin-bottom:1rem;
  }
  .price{font-size:2.9rem;font-weight:600;letter-spacing:-.045em;line-height:1;margin-bottom:1.6rem;font-variant-numeric:tabular-nums}
  .price small{font-size:.92rem;font-weight:500;color:var(--ink-3);letter-spacing:-.01em}
  .plan ul{list-style:none;margin-bottom:2rem;flex:1}
  .plan li{
    font-size:.92rem;color:var(--ink-2);padding:.42rem 0 .42rem 1.55rem;position:relative;line-height:1.5;
  }
  .plan li::before{
    content:"";position:absolute;left:0;top:.78rem;width:.55rem;height:.55rem;
    border-left:1.6px solid var(--green);border-bottom:1.6px solid var(--green);
    transform:rotate(-45deg);
  }

  /* ---------- objections ---------- */
  .pain{display:grid;grid-template-columns:repeat(2,1fr);gap:1.1rem}
  .pain .p{border:1px solid var(--rule);border-radius:12px;padding:1.9rem;background:var(--paper)}
  .pain h3{font-size:1.15rem;margin-bottom:.7rem;color:var(--ink-3);font-weight:600}
  .pain h3 s{text-decoration-color:var(--green);text-decoration-thickness:1.5px}
  .pain p{font-size:.94rem;color:var(--ink-2)}

  /* ---------- domain search ---------- */
  .domain-box{max-width:42rem;border:1px solid var(--rule-2);border-radius:12px;padding:2rem;background:var(--paper);box-shadow:var(--shadow)}
  .search-row{display:flex;gap:.6rem}
  .search-row input{
    flex:1;border:1px solid var(--rule-2);border-radius:var(--r);padding:.85rem 1rem;
    font:inherit;font-size:1rem;color:var(--ink);background:var(--paper);transition:border-color .16s,box-shadow .16s;
  }
  .search-row input::placeholder{color:var(--ink-4)}
  .search-row input:focus{outline:none;border-color:var(--green);box-shadow:0 0 0 3px var(--green-soft)}
  .result{margin-top:1.2rem;font-size:.95rem;color:var(--ink-2);min-height:1.4rem}
  .result b{color:var(--ink);font-weight:600}
  .suggest{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.9rem}
  .sug{
    background:var(--paper);border:1px solid var(--rule-2);border-radius:var(--r);
    padding:.45rem .85rem;font:inherit;font-size:.85rem;cursor:pointer;color:var(--ink-2);
    transition:border-color .16s,background .16s;
  }
  .sug:hover{border-color:var(--green);background:var(--green-soft)}
  .sug b{color:var(--green);font-weight:600;font-size:.76rem}
  .plan-pick{margin-top:1.7rem;padding-top:1.5rem;border-top:1px solid var(--rule)}
  .pick{display:flex;align-items:center;gap:.65rem;padding:.5rem 0;cursor:pointer;font-size:.94rem}
  .pick input{accent-color:var(--green);width:1rem;height:1rem}
  .pick b{font-weight:600}
  .fine{font-size:.8rem;color:var(--ink-3);margin-top:.85rem;line-height:1.55}
  .fine a{text-decoration:underline;text-underline-offset:2px}
  #buyBtn{margin-top:1.1rem}

  /* ---------- comparison ---------- */
  .cmp-wrap{border:1px solid var(--rule-2);border-radius:12px;overflow:hidden;background:var(--paper)}
  .cmp{width:100%;border-collapse:collapse;font-size:.92rem}
  .cmp th,.cmp td{padding:1rem 1.1rem;text-align:left;vertical-align:top;border-bottom:1px solid var(--rule)}
  .cmp tr:last-child td{border-bottom:0}
  .cmp th{
    font-family:"IBM Plex Mono",monospace;font-size:.63rem;letter-spacing:.11em;
    text-transform:uppercase;color:var(--ink-3);font-weight:500;background:var(--paper-2);
  }
  .cmp th.you{color:var(--green);background:var(--green-soft)}
  .cmp td.you{background:var(--green-soft);color:var(--ink-2)}
  .cmp td:first-child{color:var(--ink);font-weight:500;width:28%}
  .cmp td{color:var(--ink-3)}
  .check{color:var(--green);font-weight:700;margin-right:.25rem}

  /* ---------- pipeline ---------- */
  .pipeline{display:grid;grid-template-columns:repeat(4,1fr);gap:1.1rem}
  .step{border-top:2px solid var(--green);padding:1.4rem .2rem 0}
  .step .k{
    font-family:"IBM Plex Mono",monospace;font-size:.63rem;letter-spacing:.11em;
    text-transform:uppercase;color:var(--ink-4);display:block;margin-bottom:.9rem;
  }
  .step h3{font-size:1.2rem;margin-bottom:.55rem}
  .step p{font-size:.91rem;color:var(--ink-2)}

  /* ---------- faq ---------- */
  .faq{max-width:50rem;border:1px solid var(--rule-2);border-radius:12px;overflow:hidden;background:var(--paper)}
  .faq details{border-bottom:1px solid var(--rule)}
  .faq details:last-child{border-bottom:0}
  .faq summary{
    cursor:pointer;list-style:none;padding:1.3rem 3rem 1.3rem 1.4rem;
    font-size:1.02rem;font-weight:600;letter-spacing:-.02em;position:relative;
  }
  .faq summary::-webkit-details-marker{display:none}
  .faq summary::after{
    content:"";position:absolute;right:1.4rem;top:1.62rem;width:.5rem;height:.5rem;
    border-right:1.6px solid var(--ink-3);border-bottom:1.6px solid var(--ink-3);
    transform:rotate(45deg);transition:transform .2s;
  }
  .faq details[open] summary::after{transform:rotate(-135deg);border-color:var(--green)}
  .faq details[open] summary{color:var(--green)}
  .faq p{padding:0 3rem 1.4rem 1.4rem;color:var(--ink-2);font-size:.95rem}

  /* ---------- footer ---------- */
  footer{background:transparent;padding-top:4rem;padding-bottom:2.5rem}
  .foot-grid{
    display:grid;grid-template-columns:1.5fr repeat(4,1fr);gap:2.5rem;
    padding-bottom:3rem;border-bottom:1px solid var(--rule);
  }
  .foot-brand .logo{font-size:1.3rem}
  .foot-brand p{font-size:.87rem;color:var(--ink-3);margin-top:1rem;max-width:19rem;line-height:1.6}
  .foot-brand .call{
    display:inline-block;margin-top:1.1rem;font-weight:600;color:var(--ink);font-size:.95rem;
  }
  .foot-col h4{
    font-family:"IBM Plex Mono",monospace;font-size:.63rem;letter-spacing:.12em;
    text-transform:uppercase;color:var(--ink-4);font-weight:500;margin-bottom:1rem;
  }
  .foot-col a{
    display:block;font-size:.88rem;color:var(--ink-2);margin-bottom:.65rem;
    font-weight:500;transition:color .16s;
  }
  .foot-col a:hover{color:var(--green)}
  .foot-base{
    display:flex;justify-content:space-between;gap:1.5rem;flex-wrap:wrap;
    padding-top:1.8rem;font-size:.82rem;color:var(--ink-3);
  }
  .foot-base .status{display:flex;align-items:center;gap:.5rem;font-family:"IBM Plex Mono",monospace;font-size:.68rem;letter-spacing:.08em;text-transform:uppercase}

  /* ---------- responsive ---------- */
  @media(max-width:980px){
    .hero__inner{grid-template-columns:1fr;gap:3.2rem}
    .plans,.plans--4,.pipeline,.infra{grid-template-columns:repeat(2,1fr)}
    .infra-strip{grid-template-columns:repeat(2,1fr)}
    .infra-fig:nth-child(2){border-right:0}
    .infra-fig:nth-child(1),.infra-fig:nth-child(2){border-bottom:1px solid var(--rule)}
    .foot-grid{grid-template-columns:repeat(3,1fr)}
    .foot-brand{grid-column:1/-1}
  }
  @media(max-width:720px){
    body{font-size:16px}
    section,footer{padding:3.8rem 1.3rem}
    .hero__inner{padding:7rem 1.3rem 4rem}
    nav{padding:.85rem 1.3rem;flex-wrap:wrap;gap:1rem}
    .nav-links{gap:1.1rem;font-size:.85rem}
    .plans,.plans--4,.pipeline,.pain,.infra{grid-template-columns:1fr}
    .infra-strip{grid-template-columns:repeat(2,1fr)}
    .foot-grid{grid-template-columns:repeat(2,1fr);gap:2rem}
    .trust .wrap{gap:1.2rem}
    .trust-items{gap:1.2rem}
    .domain-box{padding:1.4rem}
    .search-row{flex-direction:column}
    .cmp{font-size:.82rem}
    .cmp th,.cmp td{padding:.75rem .6rem}
    .shot-body{grid-template-columns:5.6rem 1fr}
  }

/* ============ interior pages ============ */
.page-head{padding:4.5rem 2.2rem 3.5rem;border-bottom:1px solid var(--rule);background:var(--paper-2)}
.page-head .wrap{max-width:74rem;margin:0 auto}
.crumb{
  font-family:"IBM Plex Mono",monospace;font-size:.66rem;letter-spacing:.11em;
  text-transform:uppercase;color:var(--ink-4);margin-bottom:1.2rem;display:block;
}
.crumb a{color:var(--ink-3)}
.crumb a:hover{color:var(--green)}
.page-head h1{font-size:clamp(2.2rem,4.8vw,3.4rem);margin-bottom:1rem;max-width:26ch}
.page-head p{font-size:1.06rem;color:var(--ink-2);max-width:44rem}

.prose{max-width:44rem}
.prose h2{font-size:1.55rem;margin:2.8rem 0 .9rem;letter-spacing:-.028em}
.prose h2:first-child{margin-top:0}
.prose h3{font-size:1.12rem;margin:2rem 0 .6rem}
.prose p{color:var(--ink-2);margin-bottom:1.1rem}
.prose ul,.prose ol{margin:0 0 1.2rem 1.2rem;color:var(--ink-2)}
.prose li{margin-bottom:.5rem;padding-left:.2rem}
.prose strong{color:var(--ink);font-weight:600}
.prose a{text-decoration:underline;text-underline-offset:2px}
.prose code{
  font-family:"IBM Plex Mono",monospace;font-size:.85em;background:var(--paper-3);
  border-radius:4px;padding:.12rem .38rem;
}
.updated{
  font-family:"IBM Plex Mono",monospace;font-size:.66rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--ink-4);margin-bottom:2.2rem;display:block;
}

/* two-column article layout with sticky side nav */
.doc{display:grid;grid-template-columns:14rem minmax(0,1fr);gap:4rem;align-items:start}
.doc-nav{position:sticky;top:6rem}
.doc-nav h4{
  font-family:"IBM Plex Mono",monospace;font-size:.63rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--ink-4);font-weight:500;margin-bottom:.9rem;
}
.doc-nav a{
  display:block;font-size:.88rem;color:var(--ink-2);padding:.32rem 0;
  border-left:2px solid var(--rule);padding-left:.85rem;margin-left:-.85rem;font-weight:500;
}
.doc-nav a:hover{color:var(--green);border-left-color:var(--green)}

/* generic card grid used across interior pages */
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:1.1rem}
.grid-2{display:grid;grid-template-columns:repeat(2,1fr);gap:1.1rem}
.card{border:1px solid var(--rule-2);border-radius:12px;padding:1.7rem;background:var(--paper)}
.card svg{width:1.35rem;height:1.35rem;stroke:var(--green);fill:none;stroke-width:1.6;margin-bottom:.9rem}
.card h3{font-size:1.05rem;margin-bottom:.45rem}
.card p{font-size:.9rem;color:var(--ink-2)}
.card .name{
  font-family:"IBM Plex Mono",monospace;font-size:.64rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--ink-3);display:block;margin-bottom:.7rem;
}

/* tool cards */
.tool{
  border:1px solid var(--rule-2);border-radius:12px;padding:1.6rem;background:var(--paper);
  display:flex;flex-direction:column;transition:border-color .16s,box-shadow .16s;
}
.tool:hover{border-color:var(--green);box-shadow:var(--shadow)}
.tool h3{font-size:1.05rem;margin-bottom:.4rem}
.tool p{font-size:.89rem;color:var(--ink-2);flex:1;margin-bottom:1.1rem}
.tool .go{font-size:.85rem;font-weight:600;color:var(--green)}
.tool.soon{opacity:.6}
.tool.soon .go{color:var(--ink-4)}

/* status page rows */
.status-row{
  display:flex;align-items:center;justify-content:space-between;gap:1rem;
  padding:1.1rem 1.3rem;border-bottom:1px solid var(--rule);
}
.status-row:last-child{border-bottom:0}
.status-row b{font-weight:500;font-size:.95rem}
.status-ok{
  display:flex;align-items:center;gap:.5rem;font-family:"IBM Plex Mono",monospace;
  font-size:.66rem;letter-spacing:.1em;text-transform:uppercase;color:var(--green);
}
.panel{border:1px solid var(--rule-2);border-radius:12px;background:var(--paper);overflow:hidden}

/* contact methods */
.contact-row{display:flex;gap:1.1rem;flex-wrap:wrap;margin-bottom:2.5rem}
.contact-card{
  flex:1;min-width:15rem;border:1px solid var(--rule-2);border-radius:12px;
  padding:1.6rem;background:var(--paper);
}
.contact-card .k{
  font-family:"IBM Plex Mono",monospace;font-size:.63rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--ink-4);display:block;margin-bottom:.7rem;
}
.contact-card b{display:block;font-size:1.25rem;letter-spacing:-.03em;margin-bottom:.4rem}
.contact-card p{font-size:.87rem;color:var(--ink-3)}

@media(max-width:980px){
  .doc{grid-template-columns:1fr;gap:2.5rem}
  .doc-nav{position:static}
  .grid-3{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:720px){
  .page-head{padding:3rem 1.3rem 2.5rem}
  .grid-3,.grid-2{grid-template-columns:1fr}
}

/* ================================================================
   DARK THEME
   Set data-theme="dark" on <html>. Every colour below is a variable,
   so retuning the whole site means editing this block only.
   ================================================================ */
[data-theme="dark"]{
  --paper:#080b09;
  --paper-2:#0d1210;
  --paper-3:#141a17;
  --ink:#f1f5f3;
  --ink-2:#b4beb9;
  --ink-3:#87918c;
  --ink-4:#78827c;
  --ink-contrast:#06120c;
  --green:#3ecf8e;
  --green-hi:#5fe0a6;
  --green-soft:#0e2a1e;
  --green-line:#1d4534;
  --rule:#1b2320;
  --rule-2:#28322d;
  --nav-bg:rgba(8,11,9,.88);
  --mega-bg:#0d1210;
  --nav-hover:rgba(255,255,255,.06);
  --grain-blend:overlay;
  --grain-opacity:.10;
  --shadow:0 1px 2px rgba(0,0,0,.5),0 18px 44px -14px rgba(0,0,0,.75);
}
[data-theme="dark"] .btn-primary{background:var(--green);color:var(--ink-contrast)}
[data-theme="dark"] .btn-primary:hover{background:var(--green-hi)}
[data-theme="dark"] .nav-cta{background:var(--green);color:var(--ink-contrast)!important}
[data-theme="dark"] .nav-cta:hover{background:var(--green-hi)}
[data-theme="dark"] .shot-side u.on,[data-theme="dark"] .cmp th.you{color:var(--green)}
[data-theme="dark"] .plan.featured::before{color:var(--ink-contrast)}
[data-theme="dark"] .shot-chart i,[data-theme="dark"] .bars i{background:var(--green)}

/* buttons / ribbon use the contrast token so they invert cleanly */
.btn-primary{color:var(--ink-contrast)}
.nav-cta{color:var(--ink-contrast)!important}

/* ================================================================
   MEGA MENU
   ================================================================ */
nav{position:relative}
.nav-main{display:flex;align-items:center;gap:.15rem;list-style:none;margin:0;padding:0}
.nav-main>li{position:static}

.nav-trigger{
  display:flex;align-items:center;gap:.35rem;background:none;border:0;
  font:inherit;font-size:.9rem;font-weight:500;color:var(--ink-2);
  padding:.5rem .8rem;border-radius:var(--r);cursor:pointer;
  transition:background .16s,color .16s;letter-spacing:-.01em;
}
.nav-trigger:hover,.nav-trigger[aria-expanded="true"]{background:var(--nav-hover);color:var(--ink)}
.nav-trigger .chev{
  width:.72rem;height:.72rem;stroke:currentColor;fill:none;stroke-width:2.2;
  transition:transform .22s cubic-bezier(.3,.8,.4,1);opacity:.65;
}
.nav-trigger[aria-expanded="true"] .chev{transform:rotate(180deg)}

.mega{
  position:absolute;top:calc(100% + 1px);left:0;right:0;
  background:var(--mega-bg);border-bottom:1px solid var(--rule);
  box-shadow:var(--shadow);
  opacity:0;visibility:hidden;transform:translateY(-10px);
  transition:opacity .2s ease,transform .24s cubic-bezier(.3,.8,.4,1),visibility .24s;
  z-index:70;
}
.mega.open{opacity:1;visibility:visible;transform:translateY(0)}

.mega-inner{
  max-width:74rem;margin:0 auto;padding:2.4rem 2.2rem 2rem;
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr)) 17rem;gap:2.6rem;
}
.mega-label{
  display:block;font-family:"IBM Plex Mono",monospace;font-size:.62rem;
  letter-spacing:.14em;text-transform:uppercase;color:var(--green);
  font-weight:500;margin-bottom:1.1rem;
}
.mega-col+.mega-label{margin-top:2rem}
.mega-group+.mega-group{margin-top:1.9rem}

.mega-item{
  display:flex;align-items:flex-start;gap:.75rem;padding:.42rem .55rem;
  margin:0 -.55rem;border-radius:var(--r);transition:background .14s;
}
.mega-item:hover{background:var(--nav-hover)}
.mega-item svg{
  width:1.05rem;height:1.05rem;stroke:var(--ink-3);fill:none;stroke-width:1.6;
  flex-shrink:0;margin-top:.16rem;transition:stroke .14s;
}
.mega-item:hover svg{stroke:var(--green)}
.mega-item b{display:block;font-size:.88rem;font-weight:500;color:var(--ink);letter-spacing:-.01em}
.mega-item em{display:block;font-style:normal;font-size:.76rem;color:var(--ink-4);margin-top:.05rem}

.mega-feature{
  border-left:1px solid var(--rule);padding-left:2.2rem;
}
.mega-card{
  border:1px solid var(--rule-2);border-radius:10px;overflow:hidden;
  background:var(--paper-2);margin-bottom:1.1rem;
}
.mega-card .art{
  height:6.6rem;background:var(--green-soft);
  display:flex;align-items:flex-end;gap:3px;padding:.9rem;
}
.mega-card .art i{flex:1;background:var(--green);border-radius:2px 2px 0 0;display:block;opacity:.45}
.mega-card .art i:nth-child(n+6){opacity:1}
.mega-card .cap{padding:.85rem .95rem}
.mega-card .cap b{display:block;font-size:.85rem;font-weight:600;margin-bottom:.15rem}
.mega-card .cap span{font-size:.75rem;color:var(--ink-4)}

.mega-updates{list-style:none;margin:0;padding:0;border-left:1px solid var(--rule);padding-left:1rem}
.mega-updates li{margin-bottom:.6rem}
.mega-updates a{font-size:.82rem;color:var(--ink-2);font-weight:500}
.mega-updates a:hover{color:var(--green)}

.mega-foot{border-top:1px solid var(--rule);background:var(--paper-2)}
.mega-foot .row{
  max-width:74rem;margin:0 auto;padding:1.15rem 2.2rem;
  display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:2rem;align-items:center;
}
.mega-foot .k{
  font-family:"IBM Plex Mono",monospace;font-size:.62rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--green);
}
.mega-foot a b{display:block;font-size:.85rem;font-weight:500;color:var(--ink)}
.mega-foot a span{font-size:.75rem;color:var(--ink-4)}
.mega-foot a:hover b{color:var(--green)}

/* mobile: burger + accordion */
.nav-burger{
  display:none;background:none;border:1px solid var(--rule-2);border-radius:var(--r);
  padding:.5rem .6rem;cursor:pointer;color:var(--ink);
}
.nav-burger svg{width:1.1rem;height:1.1rem;stroke:currentColor;fill:none;stroke-width:2}

@media(max-width:1080px){
  .mega-inner{grid-template-columns:repeat(2,minmax(0,1fr));gap:2rem}
  .mega-feature{grid-column:1/-1;border-left:0;border-top:1px solid var(--rule);padding-left:0;padding-top:1.6rem}
  .mega-foot .row{grid-template-columns:repeat(2,1fr);gap:1.2rem}
}
@media(max-width:860px){
  /* The row never stacks — it scrolls. The burger is gone because
     there is nothing left for it to reveal. */
  .nav-burger{display:none}
  nav{flex-wrap:wrap;padding-block:.5rem}
  .nav-panel{width:100%;order:3}
  .mega-inner{grid-template-columns:1fr;padding:1.4rem 1.3rem 1.2rem;gap:1.4rem}
  .mega-feature{display:none}
  .mega-foot .row{grid-template-columns:1fr;padding:1rem 1.3rem;gap:.9rem}
  .nav-actions .nav-login{display:none}
}
@media(max-width:420px){
  .logo .tag{display:none}
}

/* nav internal layout — content aligns to the same 74rem column as .mega-inner */
nav{padding-inline:max(2.2rem, calc((100% - 74rem) / 2 + 2.2rem))}
.nav-panel{flex:1;display:flex;align-items:center;justify-content:space-between;gap:2rem}
.nav-actions{display:flex;align-items:center;gap:.65rem}
.nav-actions .nav-login,.nav-actions .nav-cta{font-size:.88rem;font-weight:500;white-space:nowrap}
a.nav-trigger{text-decoration:none}
@media(max-width:860px){
  nav{padding-inline:1.3rem}
  /* stays a row; the scroller handles overflow */
  .nav-panel{gap:.75rem}
}

/* ================================================================
   Header + mega menu polish — depth, gradient, smoother motion
   ================================================================ */

/* faint vertical gradient so the bar reads as a surface, not a flat strip */
nav{
  background-image:linear-gradient(to bottom,var(--nav-grad-a),var(--nav-grad-b));
  transition:box-shadow .25s ease,border-color .25s ease;
}
:root{ --nav-grad-a:rgba(255,255,255,.92); --nav-grad-b:rgba(255,255,255,.80); }
[data-theme="dark"]{ --nav-grad-a:rgba(14,19,16,.94); --nav-grad-b:rgba(8,11,9,.86); }

/* while a panel is open the bar loses its bottom edge so the two read as one surface */
nav.has-open{border-bottom-color:transparent}

.mega{
  background-image:
    radial-gradient(70rem 26rem at 78% -10%, var(--mega-glow), transparent 62%),
    linear-gradient(to bottom, var(--mega-grad-a), var(--mega-grad-b));
  transform:translateY(-12px) scale(.995);
  transform-origin:top center;
  transition:
    opacity .19s cubic-bezier(.4,0,.2,1),
    transform .3s cubic-bezier(.16,1,.3,1),
    visibility .3s;
  will-change:opacity,transform;
}
.mega.open{transform:translateY(0) scale(1)}
:root{
  --mega-grad-a:#ffffff; --mega-grad-b:#fbfcfb;
  --mega-glow:rgba(10,92,60,.05);
}
[data-theme="dark"]{
  --mega-grad-a:#111713; --mega-grad-b:#0a0e0c;
  --mega-glow:rgba(62,207,142,.10);
}

/* columns lift in just behind the panel — reads considered rather than instant */
.mega-col,.mega-feature{
  opacity:0;transform:translateY(7px);
  transition:opacity .26s ease,transform .32s cubic-bezier(.16,1,.3,1);
}
.mega.open .mega-col,
.mega.open .mega-feature{opacity:1;transform:translateY(0)}
.mega.open .mega-col:nth-child(1){transition-delay:.03s}
.mega.open .mega-col:nth-child(2){transition-delay:.06s}
.mega.open .mega-col:nth-child(3){transition-delay:.09s}
.mega.open .mega-feature{transition-delay:.12s}

/* the feature panel carries its own tint, like a lit corner of the sheet */
.mega-feature{
  background-image:linear-gradient(160deg,var(--mega-feat-a),transparent 70%);
  border-radius:0 0 12px 0;
}
:root{ --mega-feat-a:rgba(10,92,60,.045) }
[data-theme="dark"]{ --mega-feat-a:rgba(62,207,142,.075) }

.mega-card .art{
  background-image:linear-gradient(150deg,var(--green-soft),transparent 85%);
}

/* item hover gets a soft left edge instead of a flat block of colour */
.mega-item{position:relative;transition:background .16s ease,transform .16s ease}
.mega-item::before{
  content:"";position:absolute;left:0;top:12%;bottom:12%;width:2px;border-radius:2px;
  background:var(--green);opacity:0;transform:scaleY(.4);
  transition:opacity .18s ease,transform .22s cubic-bezier(.16,1,.3,1);
}
.mega-item:hover::before{opacity:1;transform:scaleY(1)}
.mega-item:hover{transform:translateX(2px)}

/* chevron eases with the panel rather than snapping */
.nav-trigger .chev{transition:transform .3s cubic-bezier(.16,1,.3,1),opacity .16s}
.nav-trigger[aria-expanded="true"]{color:var(--ink)}
.nav-trigger[aria-expanded="true"] .chev{opacity:1;color:var(--green)}

/* respect reduced-motion preferences */
@media(prefers-reduced-motion:reduce){
  .mega,.mega-col,.mega-feature,.mega-item,.nav-trigger .chev{
    transition-duration:.01ms!important;transition-delay:0ms!important;
  }
  .mega{transform:none}
}

/* mobile: the panel still drops down, but without the stagger */
@media(max-width:860px){
  .mega-col,.mega-feature{opacity:1;transform:none;transition:none}
  .mega-feature{background-image:none}
  nav{background-image:linear-gradient(to bottom,var(--nav-grad-a),var(--nav-grad-b))}
}

/* ---- footer: social row + bottom bar ---- */
.foot-social{display:flex;gap:.5rem;align-items:center}
.foot-social a{
  width:2.1rem;height:2.1rem;border:1px solid var(--rule-2);border-radius:50%;
  display:flex;align-items:center;justify-content:center;margin:0;
  transition:border-color .16s,background .16s,transform .16s;
}
.foot-social a:hover{border-color:var(--green);background:var(--green-soft);transform:translateY(-1px)}
.foot-social svg{width:1rem;height:1rem;fill:var(--ink-2)}
.foot-social a:hover svg{fill:var(--green)}
.foot-legal{display:flex;gap:1.4rem;flex-wrap:wrap;align-items:center}
.foot-legal a{margin:0;font-size:.82rem}
.foot-base{align-items:center}
@media(max-width:720px){
  .foot-base{flex-direction:column;align-items:flex-start;gap:1.2rem}
  .foot-legal{gap:1rem}
}

/* ==================================================================
   FREE TIER SIGNUP  (#free)
   The form that lets someone start without a card. Given visual
   weight on purpose — it is the first real decision on the page.
   ================================================================== */
.freewrap{
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:3rem;align-items:start;
}
.freebox{
  background:var(--paper);border:1px solid var(--rule);border-radius:14px;
  padding:2rem 1.9rem;box-shadow:var(--shadow);
}
.freebox label{
  display:block;font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-size:.68rem;letter-spacing:.11em;text-transform:uppercase;
  color:var(--ink-3);margin:0 0 .55rem;font-weight:500;
}
.freebox label + label,
.freebox .freemsg + label{margin-top:1.5rem}

/* the address field and its fixed suffix read as one control */
.subrow{
  display:flex;align-items:stretch;border:1.5px solid var(--rule-2);
  border-radius:var(--r);overflow:hidden;background:var(--paper);
  transition:border-color .16s,box-shadow .16s;
}
.subrow:focus-within{border-color:var(--green);box-shadow:0 0 0 3px var(--green-soft)}
.subrow input{
  flex:1;min-width:0;border:0;background:transparent;color:var(--ink);
  font:inherit;padding:.85rem .95rem;
}
.subrow input:focus{outline:none}
.subrow .suffix{
  display:flex;align-items:center;padding:0 .95rem;white-space:nowrap;
  background:var(--paper-2);border-left:1px solid var(--rule);
  color:var(--ink-3);font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-size:.78rem;
}
.freebox input[type=email]{
  width:100%;border:1.5px solid var(--rule-2);border-radius:var(--r);
  background:var(--paper);color:var(--ink);font:inherit;padding:.85rem .95rem;
  transition:border-color .16s,box-shadow .16s;
}
.freebox input[type=email]:focus{
  outline:none;border-color:var(--green);box-shadow:0 0 0 3px var(--green-soft);
}
.freebox .btn{width:100%;margin-top:1.5rem;justify-content:center}
.freemsg{font-size:.85rem;margin:.5rem 0 0;min-height:1.25rem;color:var(--ink-3)}
.freemsg.ok{color:var(--green-hi);font-weight:600}
.freemsg.bad{color:#a8321f;font-weight:600}
.freenote{font-size:.8rem;color:var(--ink-4);margin:.85rem 0 0;text-align:center}

.freelist{list-style:none;margin:.35rem 0 0;padding:0}
.freelist li{
  position:relative;padding-left:1.7rem;margin-bottom:1.15rem;
  color:var(--ink-2);font-size:.96rem;line-height:1.62;
}
.freelist li b{color:var(--ink);font-weight:600}
.freelist li::before{
  content:"";position:absolute;left:0;top:.62em;width:.5rem;height:.5rem;
  border-radius:50%;background:var(--green);
}
@media(max-width:860px){
  .freewrap{grid-template-columns:1fr;gap:2.2rem}
}

/* ==================================================================
   EMAIL CAPTURE  (#keepme and the domain-search fallback)
   ================================================================== */
.capture{
  border:1px solid var(--green-line);background:var(--green-soft);
  border-radius:12px;padding:1.4rem 1.5rem;margin-top:1.5rem;
}
.capture h4{font-size:1.02rem;margin-bottom:.35rem;letter-spacing:-.02em}
.capture p{color:var(--ink-2);font-size:.9rem;margin-bottom:.9rem}
.caprow{display:flex;gap:.6rem;flex-wrap:wrap}
.caprow input{
  flex:1;min-width:12rem;border:1.5px solid var(--green-line);border-radius:var(--r);
  background:var(--paper);color:var(--ink);font:inherit;padding:.75rem .9rem;
}
.caprow input:focus{outline:none;border-color:var(--green)}
.caprow .btn{flex:none}
.capmsg{font-size:.85rem;margin:.7rem 0 0;min-height:1.1rem;color:var(--green-hi);font-weight:600}

/* ==================================================================
   NAV: horizontal trigger strip
   ------------------------------------------------------------------
   The top-level row is one line, always. It never wraps and never
   stacks — at any width narrower than its content it becomes a
   sideways scroller, on phones and on a squashed desktop window
   alike. The dropdown still opens full-width beneath it.

   This works because the .mega panels are siblings of .nav-main
   rather than descendants: an ancestor with overflow-x:auto clips
   absolutely positioned children, so a panel inside the scroller
   would be cut off the moment the row overflowed.
   ================================================================== */
.nav-main{
  display:flex;align-items:center;gap:.15rem;
  list-style:none;margin:0;padding:0;
  flex-wrap:nowrap;                    /* the whole point: never stack */
  overflow-x:auto;overflow-y:hidden;
  scrollbar-width:none;                /* Firefox */
  -ms-overflow-style:none;             /* old Edge */
  -webkit-overflow-scrolling:touch;    /* iOS momentum */
  overscroll-behavior-x:contain;       /* don't trigger back-swipe */
  scroll-snap-type:x proximity;
  scroll-padding-inline:1rem;
  min-width:0;                         /* let it shrink inside the flex row */
}
.nav-main::-webkit-scrollbar{display:none}
.nav-main>li{flex:0 0 auto;scroll-snap-align:start}
.nav-trigger{white-space:nowrap}

/* Edge fades, toggled from JS so they only show on the side that
   actually has more to scroll toward. A permanent mask would dim the
   first and last item even on a wide screen with nothing hidden. */
.nav-panel{position:relative}
.nav-panel::before,
.nav-panel::after{
  content:"";position:absolute;top:0;bottom:0;width:2.2rem;
  pointer-events:none;z-index:4;opacity:0;transition:opacity .18s ease;
}
.nav-panel::before{left:0;background:linear-gradient(to right,var(--nav-grad-a),transparent)}
.nav-panel::after{right:0;background:linear-gradient(to left,var(--nav-grad-a),transparent)}
nav.can-left  .nav-panel::before{opacity:1}
nav.can-right .nav-panel::after{opacity:1}

/* Panels are absolute at every width now, so "drops down when
   clicked" behaves the same on a phone as on a desktop. */
.mega{
  position:absolute;top:calc(100% + 1px);left:0;right:0;
  max-height:min(78vh, 42rem);overflow-y:auto;
  overscroll-behavior:contain;
}

@media(max-width:860px){
  /* the strip gets a hairline above it so it reads as its own band */
  .nav-panel{
    border-top:1px solid var(--rule);
    margin-top:.5rem;padding-top:.5rem;
  }
  .nav-main{gap:.1rem}
  .nav-trigger{padding:.6rem .7rem;font-size:.9rem}
  /* full-bleed dropdown on phones */
  .mega{
    left:-1.3rem;right:-1.3rem;
    border-radius:0;max-height:72vh;
  }
}

/* A visible scrollbar is noise, but keyboard users still need to see
   where they are. Focus ring stays on, and the strip scrolls to it. */
.nav-main .nav-trigger:focus-visible{outline:2px solid var(--green);outline-offset:-2px}

@media(prefers-reduced-motion:reduce){
  .nav-main{scroll-behavior:auto;scroll-snap-type:none}
  .nav-panel::before,.nav-panel::after{transition:none}
}

/* Only when the strip actually overflows: breathing room at the ends so
   the first and last trigger aren't jammed under the edge fades. */
nav.nav-scrolls .nav-main{padding-inline:.15rem .9rem}

/* The strip takes whatever width is left beside the CTA and scrolls
   inside it. On a phone that keeps "Start Free" permanently visible
   next to the menu instead of pushing it onto its own row. */
.nav-main{flex:1 1 auto}
.nav-actions{flex:0 0 auto}

/* ==================================================================
   PAID PLACEMENT
   Clearly labelled as advertising, visually quieter than our own
   content. An ad that looks like editorial is a dark pattern and
   breaks disclosure rules in most places we'd want customers.
   ================================================================== */
#adslot{padding-block:0}
.adcard{max-width:44rem;margin:0 auto}
.adlink{
  display:block;border:1px solid var(--rule);border-radius:12px;
  padding:1.3rem 1.5rem;text-decoration:none;color:inherit;
  background:var(--paper-2);transition:border-color .16s,transform .16s;
}
.adlink:hover{border-color:var(--green-line);transform:translateY(-1px)}
.adlabel{
  display:block;font-family:"IBM Plex Mono",ui-monospace,monospace;
  font-size:.62rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-4);margin-bottom:.5rem;
}
.adlink b{display:block;font-size:1.05rem;letter-spacing:-.02em;margin-bottom:.25rem}
.adbody{display:block;color:var(--ink-2);font-size:.92rem;line-height:1.6}

/* ==========================================================================
   HERO BACKDROP
   Full-bleed animated ground behind the hero, the way a photograph or a
   video would sit there. Drawn rather than shot, because there are no
   assets and a generic stock photo is worse than none.

   Pure CSS and one inline SVG. No script, no network request, nothing the
   headline has to wait for: the first paint already has the finished
   backdrop in it. A video here would be heavier, would arrive later, and
   would refuse to autoplay on an iPhone in Low Power Mode.

   Every colour derives from the theme. Same geometry light or dark, with
   inverted material: silhouettes on paper by day, lit windows by night.
   ========================================================================== */

/* The hero is full-bleed by being full width, not by stretching a child to
   100vw. 100vw counts the scrollbar, which forced overflow-x:clip on the
   root, and a clip context on the root stops position:sticky working: the
   nav had quietly stopped sticking on every page of the site. */
.hero{ position:relative; z-index:0; }

.hero__bg{
  position:absolute; z-index:0;
  inset:0;
  overflow:hidden;
  pointer-events:none;
  --hero-win:rgba(12,18,16,.10);
  --hero-l1:rgba(12,18,16,.055);
  --hero-l2:rgba(12,18,16,.085);
  --hero-l3:rgba(12,18,16,.13);
  --hero-sky-a:var(--gd, var(--paper));
  --hero-sky-b:color-mix(in srgb, var(--gd, var(--paper)) 92%, var(--ink));
  --hero-halo:rgba(10,92,60,.10);
  --hero-star:transparent;
}

[data-theme="dark"] .hero__bg{
  --hero-win:rgba(62,207,142,.55);
  --hero-l1:#0b100e;
  --hero-l2:#0d1411;
  --hero-l3:#101815;
  --hero-sky-a:#050807;
  --hero-sky-b:#080b09;
  --hero-halo:rgba(62,207,142,.16);
  --hero-star:rgba(215,235,225,.55);
}

/* Sky. Two stops plus a halo sitting where the skyline meets it, so the
   silhouette has something to be a silhouette against. */
.hero__sky{
  position:absolute; inset:0;
  background:
    radial-gradient(120% 62% at 50% 96%, var(--hero-halo) 0%, transparent 62%),
    linear-gradient(180deg, var(--hero-sky-a) 0%, var(--hero-sky-b) 100%);
}

/* Stars, on dark only: three tiled gradients rather than elements. */
.hero__stars{
  position:absolute; inset:0 0 34% 0;
  background-image:
    radial-gradient(1.4px 1.4px at 18% 22%, var(--hero-star), transparent 100%),
    radial-gradient(1.2px 1.2px at 63% 12%, var(--hero-star), transparent 100%),
    radial-gradient(1.6px 1.6px at 82% 38%, var(--hero-star), transparent 100%),
    radial-gradient(1.1px 1.1px at 37% 47%, var(--hero-star), transparent 100%),
    radial-gradient(1.3px 1.3px at 91% 8%,  var(--hero-star), transparent 100%),
    radial-gradient(1.2px 1.2px at 8%  58%, var(--hero-star), transparent 100%);
  opacity:.85;
  animation:hero-breathe 11s ease-in-out infinite;
}

.hero-skyline{
  position:absolute; left:0; right:0; bottom:0;
  width:100%; height:min(62%, 30rem);
  display:block;
}
.hl1 rect{ fill:var(--hero-l1) }
.hl2 rect{ fill:var(--hero-l2) }
.hl3 rect{ fill:var(--hero-l3) }

/* Lit windows, dark only. Swapping the fill to a pattern is what turns the
   silhouette into an occupied city, and it costs two pattern definitions
   rather than a rect per window. By day the bands stay flat silhouettes,
   because windows on a white sky read as noise. */
[data-theme="dark"] .hl2 rect{ fill:url(#ew2) }
[data-theme="dark"] .hl3 rect{ fill:url(#ew3) }

/* Parallax drift. Further bands travel slower, which is the whole illusion.
   Each band is drawn twice, so translating one tile width loops seamlessly
   and there is never a visible jump. transform only: no layout, no paint. */
.hl{ will-change:transform }
.hl1{ animation:hero-drift 210s linear infinite }
.hl2{ animation:hero-drift 132s linear infinite }
.hl3{ animation:hero-drift  84s linear infinite }

@keyframes hero-drift{
  from{ transform:translateX(0) }
  to  { transform:translateX(-1200px) }
}
@keyframes hero-breathe{
  0%,100%{ opacity:.85 }
  50%    { opacity:.45 }
}

/* A single slow sweep of light across the city, so the frame is alive even
   where nothing is drifting. One element, one transform, 26 seconds. */
.hero__sweep{
  position:absolute; top:0; bottom:0; left:0;
  width:38%;
  background:linear-gradient(90deg, transparent, var(--hero-halo), transparent);
  opacity:.55;
  animation:hero-sweep 26s cubic-bezier(.45,0,.55,1) infinite;
}
@keyframes hero-sweep{
  0%   { transform:translateX(-45%) }
  50%  { transform:translateX(300%) }
  100% { transform:translateX(-45%) }
}

/* The scrim is shaped to where the copy actually is: a column on the reading
   side, not a full-frame overlay that throws the whole picture away. Below
   860px the copy spans the frame, so it becomes a band. */
.hero__veil{
  position:absolute; inset:0;
  background:linear-gradient(90deg,
    var(--gd, var(--paper)) 0%, var(--gd, var(--paper)) 26%,
    color-mix(in srgb, var(--gd, var(--paper)) 72%, transparent) 52%,
    transparent 78%);
}
@supports not (color: color-mix(in srgb, red, blue)){
  .hero__veil{ background:linear-gradient(90deg,var(--paper) 0%,var(--paper) 30%,transparent 80%) }
}

/* Give the hero the height that makes a full-bleed ground worth having,
   without letting it overflow: the headline and the CTA still land above
   the fold. svh, with a vh floor for anything that does not know svh. */
header.hero{ min-height:82vh }
.hero__inner{ position:relative; z-index:1 }
@supports (height:100svh){ header.hero{ min-height:82svh } }

/* The product mock-up sits ON the ground now, so it needs its own edge. */
.hero .shot{ position:relative; backdrop-filter:blur(3px) }

@media (max-width:860px){
  .hero__veil{
    background:linear-gradient(0deg,
      var(--gd, var(--paper)) 0%, var(--gd, var(--paper)) 34%,
      color-mix(in srgb, var(--gd, var(--paper)) 74%, transparent) 62%,
      transparent 100%);
  }
  @supports not (color: color-mix(in srgb, red, blue)){
    .hero__veil{ background:linear-gradient(0deg,var(--paper) 0%,var(--paper) 40%,transparent 100%) }
  }
  .hero-skyline{ height:min(46%, 18rem) }
  header.hero{ min-height:0 }
  .hero .shot{ backdrop-filter:none }
}

/* Reduced motion: fewer and gentler, not zero. The city stays, fully drawn
   and fully legible. Only the travel stops. */
@media (prefers-reduced-motion:reduce){
  .hl1,.hl2,.hl3,.hero__stars,.hero__sweep{ animation:none }
  .hero__sweep{ opacity:.28 }
}

/* ---- hero video rotation -------------------------------------------------
   The drawn skyline stays underneath as the fallback ground. These layers
   only appear once a clip is actually playing, so a blocked autoplay leaves
   the hero exactly as it was rather than leaving a black rectangle. */
.hero__video{ position:absolute; inset:0; overflow:hidden }
.hero__video video{
  position:absolute; inset:0;
  width:100%; height:100%;
  object-fit:cover;
  opacity:0;
  transition:opacity 1.1s cubic-bezier(.4,0,.2,1);
  will-change:opacity;
}
.hero__video video.on{ opacity:1 }

/* Once video is running the drawn city would show through it, and the sweep
   and stars belong to the drawn version only. */
.hero__bg.has-video .hero-skyline,
.hero__bg.has-video .hero__stars,
.hero__bg.has-video .hero__sweep{ opacity:0; transition:opacity .8s ease-out }

/* The scrim, set from a measurement rather than by eye.

   Peak luma in the copy column across the eight clips runs from 64 to 186.
   White text on 186 is 1.95:1, which is unreadable, so the scrim has to be
   graded for the WORST clip, not the average, or the hero is legible seven
   times out of eight and nobody can reproduce the complaint.

   At .58 over the brightest clip the composite lands near 8.5:1, and the
   footage is still 42% visible where the reader is looking. It is a graded
   column, not a full-frame overlay: the right-hand side keeps its picture.
   `--paper` does the theme work for free, whitening on light and darkening
   on dark. */
.hero__bg.has-video .hero__veil{
  background:linear-gradient(90deg,
    color-mix(in srgb, var(--gd, var(--paper)) 74%, transparent) 0%,
    color-mix(in srgb, var(--gd, var(--paper)) 58%, transparent) 38%,
    color-mix(in srgb, var(--gd, var(--paper)) 26%, transparent) 68%,
    color-mix(in srgb, var(--gd, var(--paper)) 15%, transparent) 100%);
}
@supports not (color: color-mix(in srgb, red, blue)){
  /* Without color-mix there is no theme-aware alpha, so fall back to a flat
     pair and accept a heavier scrim rather than an unreadable headline. */
  .hero__bg.has-video .hero__veil{ background:linear-gradient(90deg,rgba(0,0,0,.72),rgba(0,0,0,.22)) }
  :root:not([data-theme="dark"]) .hero__bg.has-video .hero__veil{
    background:linear-gradient(90deg,rgba(255,255,255,.86),rgba(255,255,255,.34));
  }
}

@media (max-width:860px){
  /* The copy spans the frame on a phone, so the column becomes a band. */
  .hero__bg.has-video .hero__veil{
    background:linear-gradient(0deg,
      color-mix(in srgb, var(--gd, var(--paper)) 82%, transparent) 0%,
      color-mix(in srgb, var(--gd, var(--paper)) 64%, transparent) 46%,
      color-mix(in srgb, var(--gd, var(--paper)) 22%, transparent) 100%);
  }
  @supports not (color: color-mix(in srgb, red, blue)){
    .hero__bg.has-video .hero__veil{ background:linear-gradient(0deg,rgba(0,0,0,.8),rgba(0,0,0,.2)) }
  }
}

/* No clip is ever fetched under reduced motion: the script returns before it
   creates an element. This is belt and braces for anything already mounted. */
@media (prefers-reduced-motion:reduce){
  .hero__video{ display:none }
  .hero__bg.has-video .hero-skyline,
  .hero__bg.has-video .hero__stars{ opacity:1 }
}


/* ==================================================================
   SECTION GROUNDS
   Flat colour, no gradients, no rules between blocks. Sections are
   grouped into chapters and a chapter change is a change of ground,
   which is the only separator the page needs.

   Three grounds and one accent block. Two grounds that are nearly the
   same is exactly the mistake this replaces, so the steps are real:
   void to pine is a 1.23 luminance ratio, pine to forest 1.30.

   Every ground restates `color` as well as redefining --ink. It has to:
   `color` inherits as a COMPUTED value, so text whose colour already
   resolved on <body> keeps the body's ink no matter what a subtree
   redefines the token to. That failure is silent, and it renders bone
   type on near-black at about 1.1:1 while every token looks correct.

   Contrast was measured for all four inks plus the accent on all three
   grounds, both themes. Worst pairing is 4.61:1.
   ================================================================== */
[data-ground]{ background:var(--gd); color:var(--ink) }

:root{
  --gd-void:#ffffff;   --gd-pine:#eef4f0;   --gd-forest:#dde9e2;
  --gd-accent:#0a5c3c;
}
[data-theme="dark"]{
  --gd-void:#050706;   --gd-pine:#08241c;   --gd-forest:#0d3a2b;
  --gd-accent:#0a5c3c;
}

[data-ground="void"]  { --gd:var(--gd-void) }
[data-ground="pine"]  { --gd:var(--gd-pine) }
[data-ground="forest"]{ --gd:var(--gd-forest) }

/* Muted inks lift with the ground so the quietest text never drops under
   4.5:1 on the deepest block. On light they darken instead: same idea,
   opposite direction. */
[data-ground="pine"]  { --ink:#0b1210; --ink-2:#404a45; --ink-3:#56625c; --ink-4:#616d68; --green:#095436 }
[data-ground="forest"]{ --ink:#0a110f; --ink-2:#3b4540; --ink-3:#4e5a54; --ink-4:#586460; --green:#084d32 }
[data-theme="dark"] [data-ground="void"]  { --ink:#f1f5f3; --ink-2:#b4beb9; --ink-3:#8d978f; --ink-4:#7c877f; --green:#3ecf8e }
[data-theme="dark"] [data-ground="pine"]  { --ink:#f2f7f4; --ink-2:#bdc9c1; --ink-3:#9aa79e; --ink-4:#8b998f; --green:#54dc9e }
[data-theme="dark"] [data-ground="forest"]{ --ink:#f4f8f5; --ink-2:#c8d3ca; --ink-3:#a8b4aa; --ink-4:#9aa79c; --green:#6ee5ad }

/* The rules a ground implies. Hairlines inside a block still earn their
   place; hairlines BETWEEN blocks were the problem. */
[data-ground]{ --rule:color-mix(in srgb, var(--ink) 12%, transparent);
               --rule-2:color-mix(in srgb, var(--ink) 20%, transparent) }

/* ---- the join ----------------------------------------------------
   A ground change tucks under the block above it on a large radius.
   That overlap IS the transition: no line, no fade, just one surface
   passing behind another. `position:relative` and a z-index step keep
   the newer block on top so the corners read as corners. */
[data-ground][data-join]{
  position:relative;
  border-radius:var(--gd-r) var(--gd-r) 0 0;
  margin-top:calc(var(--gd-r) * -1);
  padding-top:calc(5.5rem + var(--gd-r));
  z-index:1;
}
/* Every grounded block reserves the overlap below it. Without this the
   next chapter's rounded top slides over the last line of the block
   above, and a caption simply loses its final row of text. */
[data-ground]{ padding-bottom:calc(5.5rem + var(--gd-r)) }
@media (max-width:720px){
  [data-ground]{ padding-bottom:calc(3.8rem + var(--gd-r)) }
  [data-ground][data-join]{ padding-top:calc(3.8rem + var(--gd-r)) }
}
:root{ --gd-r:clamp(1.5rem, 4vw, 3.5rem) }

/* The last block before the footer closes its shape at the bottom too,
   so the page ends on a resolved form rather than a cut edge. */
[data-ground][data-join="close"]{ border-radius:var(--gd-r); margin-bottom:var(--gd-r) }

/* The accent block: one per page, the close. Dark ink on green by day,
   the same green with light ink by night. */
[data-ground="accent"]{
  --gd:var(--gd-accent);
  --ink:#ffffff; --ink-2:#cfe6da; --ink-3:#b3d7c4; --ink-4:#a6cfba;
  --green:#ffffff;
}
[data-ground="accent"] .btn-primary{ background:#ffffff; color:#0a5c3c }
[data-ground="accent"] .btn-primary:hover{ background:#eaf6ef }
[data-ground="accent"] .btn-ghost{ border-color:rgba(255,255,255,.45); color:#ffffff }
[data-ground="accent"] .btn-ghost:hover{ border-color:#fff; background:rgba(255,255,255,.10) }

@media (prefers-reduced-motion:no-preference){
  /* Nothing animates on a ground change: the colour IS the event. A
     cross-fading background is the busy-ness this replaces. */
}


/* ==================================================================
   OVERLAY HEADER  (homepage only, via body[data-nav="overlay"])

   The header was a 110px black band sitting ABOVE the hero: a black
   ribbon on top of a dark nav on top of the video. Three separate
   dark bars reading as chrome bolted to the page.

   Now it sits ON the hero. The ribbon and the nav are transparent and
   the film runs behind them, so the first thing on the page is the
   picture and not a toolbar. The nav takes a real background only
   when it needs one: once it leaves the hero, or whenever a mega
   panel is open, because a panel hanging off a transparent bar reads
   as floating rather than attached.

   Scoped to the homepage. Every other page keeps the solid sticky
   header it already had, which is correct there: those pages have no
   hero for the nav to sit on.
   ================================================================== */
body[data-nav="overlay"] nav{
  position:fixed; top:0; left:0; right:0; z-index:60;
  background:transparent; background-image:none;
  backdrop-filter:none; border-bottom-color:transparent;
  transition:background-color .24s var(--ease,cubic-bezier(.23,1,.32,1)),
             top .24s var(--ease,cubic-bezier(.23,1,.32,1)),
             border-color .24s;
}
/* Solid once it leaves the hero, or whenever a panel is open. */
body[data-nav="overlay"] nav.is-stuck,
body[data-nav="overlay"] nav.has-open{
  top:0;
  background:var(--nav-bg);
  backdrop-filter:saturate(180%) blur(14px);
  border-bottom-color:var(--rule);
}
body[data-nav="overlay"] nav.has-open{ background:var(--mega-bg); backdrop-filter:none }

/* Legibility for the nav over whichever clip happens to be playing. The
   brightest clip in the set peaks at 186 luma, so the top band is graded
   for that one rather than for the average. */
body[data-nav="overlay"] .hero__bg::after{
  content:""; position:absolute; top:0; left:0; right:0;
  height:13rem; z-index:4; pointer-events:none;
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--gd, var(--paper)) 90%, transparent) 0%,
    color-mix(in srgb, var(--gd, var(--paper)) 55%, transparent) 42%,
    transparent 100%);
}
@supports not (color: color-mix(in srgb, red, blue)){
  body[data-nav="overlay"] .hero__bg::after{
    background:linear-gradient(180deg,rgba(0,0,0,.85),rgba(0,0,0,.4) 42%,transparent);
  }
}

/* The panel is a solid surface hanging off a solid bar. */
body[data-nav="overlay"] nav.has-open .mega{ box-shadow:0 24px 60px -24px rgba(0,0,0,.75) }

@media (max-width:860px){
  body[data-nav="overlay"] .hero__bg::after{ height:9rem }
}

/* ==================================================================
   PHOTOGRAPHY

   Three shapes, deliberately different, because a page that shows its
   photographs in one repeated 3-up grid reads as a template. A band of
   three, an asymmetric pair, and a single wide plate. Never more than
   three in a section.

   Every figure carries its aspect ratio in CSS and its real pixel
   dimensions on the <img>, so nothing reflows as the photos arrive.
   Both width and height are overridden together: setting only one
   leaves the other resolving to the attribute's raw value, which is
   how a 700x1050 photo ends up 1050px tall inside a narrow column and
   pushes everything below it off the fold.
   ================================================================== */
/* The source photographs are 612px wide. Anything shown much beyond that
   is upscaling, which is what made the bands look soft: they were sitting
   OUTSIDE .wrap and stretching across the whole viewport. Inside .wrap a
   3-up cell is about 363px, so each photo renders at ~1.7x density and is
   sharp even on a retina screen. The single wide plate is capped for the
   same reason rather than being allowed to fill 1184px. */
.shots{ display:grid; gap:clamp(.9rem,2vw,1.4rem); margin-top:2.4rem }
/* align-items:start, not the default stretch. Stretched grid items are
   forced to the height of the tallest, and a figure whose image also had
   height:100% then reported a box shorter than its own contents — so the
   caption spilled out of the grid and landed on top of whatever followed.
   That is exactly what happened on the templates page: the paragraph
   below the three cards was overprinted by three captions. */
.shots--3{ grid-template-columns:repeat(3,1fr); align-items:start }
/* Not 50/50: an asymmetric pair reads as composition, an even one reads
   as a table with two cells. */
.shots--pair{ grid-template-columns:minmax(0,1.3fr) minmax(0,1fr); align-items:end;
              max-width:62rem }
.shots--wide{ grid-template-columns:1fr; margin-top:2.2rem; align-items:start;
              max-width:56rem; margin-inline:auto }

.shot-fig{ margin:0; position:relative }
.shot-fig img{
  /* height:auto, NOT 100%. Every one of these images has an aspect-ratio
     below, which is what should decide the height. height:100% made the
     image claim the whole stretched cell and left the caption outside the
     box the figure reported — which is the overlap on the templates page. */
  display:block; width:100%; height:auto;
  object-fit:cover;
  border-radius:clamp(.7rem,1.4vw,1.1rem);
  background:color-mix(in srgb, var(--ink) 8%, transparent);
}
.shots--3 .shot-fig img{ aspect-ratio:4/3 }
.shots--pair .shot-fig:first-child img{ aspect-ratio:16/10 }
.shots--pair .shot-fig:last-child img{ aspect-ratio:4/5 }
.shots--wide .shot-fig img{ aspect-ratio:12/5 }

.shot-fig figcaption{
  margin-top:1rem; color:var(--ink-2);
  position:relative; z-index:0;
  font-size:.95rem; line-height:1.55; max-width:34ch;
}
.shot-fig figcaption b{
  display:block; color:var(--ink); font-weight:600;
  font-size:1.05rem; letter-spacing:-.02em; margin-bottom:.3rem;
}

/* A caption laid over the plate, for the single wide shot only. The
   gradient is a band across the bottom third, not a full-frame wash. */
.shot-fig--over figcaption{
  position:absolute; left:0; right:0; bottom:0; max-width:none;
  margin:0; padding:clamp(1.4rem,4vw,2.6rem);
  color:#fff;
  background:linear-gradient(0deg,rgba(0,0,0,.78) 0%,rgba(0,0,0,.42) 55%,transparent 100%);
  border-radius:0 0 clamp(.7rem,1.4vw,1.1rem) clamp(.7rem,1.4vw,1.1rem);
}
.shot-fig--over figcaption b{ color:#fff; font-size:clamp(1.1rem,2.4vw,1.6rem) }

/* A photo beside a block of prose, for sections that already have their
   own content and just need air. */
.shot-aside{
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,.78fr);
  gap:clamp(1.6rem,4vw,3.4rem); align-items:center;
}
.shot-aside img{
  display:block; width:100%; height:auto;
  border-radius:clamp(.7rem,1.4vw,1.1rem);
  aspect-ratio:5/4; object-fit:cover;
}

@media (max-width:900px){
  .shots--3{ grid-template-columns:1fr 1fr }
  /* The third photo spans the row rather than leaving an empty cell: a
     grid with a blank trailing tile was planned wrong. */
  .shots--3 .shot-fig:nth-child(3){ grid-column:1 / -1 }
  .shots--3 .shot-fig:nth-child(3) img{ aspect-ratio:16/9 }
  .shots--pair{ grid-template-columns:1fr; align-items:stretch }
  .shots--pair .shot-fig img{ aspect-ratio:16/10 }
  .shot-aside{ grid-template-columns:1fr; gap:1.8rem }
}
@media (max-width:560px){
  .shots--3{ grid-template-columns:1fr }
  .shots--3 .shot-fig:nth-child(3){ grid-column:auto }
  .shots--3 .shot-fig img,
  .shots--3 .shot-fig:nth-child(3) img{ aspect-ratio:16/10 }
  .shots--wide .shot-fig img{ aspect-ratio:4/3 }
}

/* ==================================================================
   NARROW-WIDTH FIXES
   Found by measuring the real page in a browser at 390px, not by
   reading the stylesheet: at 390 the document scrolled sideways by
   103px and the whole page could be dragged.
   ================================================================== */

/* A grid item's min-width is `auto`, which means it refuses to go
   narrower than its own min-content and simply overflows its track
   instead. `.subrow .suffix` is white-space:nowrap holding
   ".empiresitebuilder.com" in monospace, so the free-signup card had a
   473px floor and pushed 103px past a 390px phone. The track was fine;
   the item was the problem. */
.freewrap > *{ min-width:0 }
.freebox{ min-width:0 }
.subrow{ min-width:0 }

/* Below 560 the suffix stops being an inline addendum and becomes a
   second line, so the address stays fully readable instead of being
   truncated to "...sitebuil". Truncating the thing the visitor is
   about to claim would be the wrong trade. */
@media (max-width:560px){
  .subrow{ flex-wrap:wrap }
  .subrow input{ flex:1 0 100%; padding-bottom:.6rem }
  .subrow .suffix{
    flex:1 0 100%; justify-content:flex-start;
    border-left:0; border-top:1px solid var(--rule);
    padding-top:.55rem; padding-bottom:.6rem;
  }
}

/* Touch targets. 26 footer links and the wordmark were rendering
   between 17 and 24px tall, which is under any reasonable thumb.
   Padding rather than height, so the type keeps its own rhythm and the
   columns do not change shape. */
@media (max-width:860px){
  footer a{ display:inline-block; padding-block:.42rem }
  .foot-grid a{ padding-block:.5rem }
  .foot-bottom a{ padding-block:.45rem }
  nav .logo{ display:flex; flex-direction:column; justify-content:center; min-height:44px }
  .fine a, .freenote a, .micro a, .freecta a{ padding-block:.4rem; display:inline-block }
}

/* ==================================================================
   TYPE SCALE

   The page had roughly twenty one-off sizes (.9, .91, .92, .94, .95,
   .96, 1.02, 1.05, 1.06, 1.12, 1.15rem) with no relationship between
   them, one line-height of 1.04 applied to every heading from 4.5rem
   down to 1.05rem, and one tracking of -.032em applied the same way.
   That is what reads as "not quite premium": at 4.5rem, 1.04 and
   -.042em are correct; at 1.05rem the identical values are cramped.

   Two corrections, both optical rather than mathematical:
     line-height goes UP as size goes down
     tracking goes toward 0 as size goes down
   ================================================================== */
:root{
  --t-2xs:.72rem;  --t-xs:.8rem;   --t-sm:.9rem;
  --t-base:1rem;   --t-md:1.125rem;
  --t-lg:1.28rem;
  --t-xl: clamp(1.45rem, 1.1rem + 1.1vw, 1.8rem);
  --t-2xl:clamp(1.8rem, 1.2rem + 2.1vw, 2.4rem);
  --t-3xl:clamp(2.15rem, 1.3rem + 3.4vw, 3.2rem);
  --t-4xl:clamp(2.6rem, 1.2rem + 5.4vw, 4.6rem);

  --lh-display:1.02;  --lh-heading:1.16;  --lh-sub:1.35;  --lh-body:1.62;
  --tr-display:-.042em; --tr-heading:-.028em; --tr-sub:-.015em; --tr-body:0;
}

h1{ font-size:var(--t-4xl); line-height:var(--lh-display); letter-spacing:var(--tr-display) }
h2, .sec-head h2{ font-size:var(--t-3xl); line-height:1.06; letter-spacing:-.036em }
.page-head h1{ font-size:var(--t-3xl); line-height:1.05; letter-spacing:-.036em }

/* Anything at heading weight but body scale gets its own metrics: this is
   the group that was being set at 1.04/-.032em and reading squeezed. */
h3,
.infra-card h3, .pain h3, .step h3, .card h3, .tool h3, .capture h4,
.prose h3, .shot-fig figcaption b, .plan .name + *{
  font-size:var(--t-md); line-height:var(--lh-heading); letter-spacing:var(--tr-heading);
}
.pain h3, .step h3{ font-size:var(--t-lg) }
.prose h2{ font-size:var(--t-xl); line-height:var(--lh-heading); letter-spacing:var(--tr-heading) }

/* The lede was 1.1rem against a 17px body: a 0.6px difference is not a
   hierarchy, it is a rounding error. */
.lede, .sec-head p, .page-head p{
  font-size:var(--t-md); line-height:var(--lh-sub); letter-spacing:var(--tr-sub);
  text-wrap:pretty;
}
.hero .lede{ font-size:clamp(1.05rem, .95rem + .35vw, 1.22rem); line-height:1.5 }

/* Everything that was a one-off decimal, mapped onto the scale. */
.infra-card p, .pain p, .step p, .faq p, .card p, .tool p,
.contact-card p, .capture p, .foot-brand p, .plan li, .cmp,
.freelist li, .shot-fig figcaption, .adbody, .capmsg, .pick{
  font-size:var(--t-sm); line-height:var(--lh-body); letter-spacing:var(--tr-body);
}
.freelist li, .plan li{ line-height:1.55 }

/* Headings balance, prose is set for reading rather than for the container. */
h1, h2, h3{ text-wrap:balance }
.lede, .sec-head p, .page-head p, .faq p, .prose p{ max-width:62ch }

/* Light-on-dark needs a touch more leading and tracking than the same
   type would want on paper, or it reads thin and blurry. */
[data-theme="dark"] body{ letter-spacing:.004em }
[data-theme="dark"] .lede,
[data-theme="dark"] .sec-head p{ letter-spacing:calc(var(--tr-sub) + .006em) }

@media (max-width:560px){
  /* clamp's lower bound is still a desktop floor at 390px. */
  h1{ font-size:clamp(2.1rem, 1.1rem + 5.2vw, 2.7rem) }
  h2, .sec-head h2{ font-size:clamp(1.7rem, 1rem + 3.6vw, 2.1rem) }

  /* The hero eyebrow — "Your business deserves better than a Facebook
     page" — is hidden on phones.
     ---------------------------------------------------------------
     The navigation wraps onto two rows on a narrow screen, which makes
     the fixed header taller than the hero's top padding was calculated
     for, and the eyebrow ends up printed THROUGH the nav links. There is
     already a fix for this further down, but it is scoped to
     max-height:680px — short phones only — so a tall modern handset
     still collided.

     Hiding it rather than adding more padding is the right trade on a
     phone: it is a supporting line, the headline immediately below says
     the same thing with more force, and every rem spent clearing it is a
     rem the actual offer is pushed below the fold. It still shows on
     wider screens, where there is room and no collision. */
  .hero__inner .mono{ display:none }
}

/* ---- cycling headline word -------------------------------------------
   The word slides up and the next one arrives from below, and the box
   animates its width so the line never jumps. transform and opacity for
   the motion, width for the box: width is the one property here that
   cannot be done on the compositor, but it is one element changing a few
   times a minute, not a scroll-linked effect. */
.cyc{ display:inline-block; vertical-align:top }
.cyc__win{
  display:inline-block; overflow:hidden; vertical-align:top;
  height:1em; line-height:inherit;
  width:var(--cyc-w, auto);
  transition:width .52s cubic-bezier(.22,1,.32,1);
}
.cyc__list{
  display:block;
  transform:translateY(calc(var(--cyc-i, 0) * -1em));
  transition:transform .52s cubic-bezier(.22,1,.32,1);
  will-change:transform;
}
.cyc__list i{
  display:block; height:1em; line-height:inherit;
  font-style:normal; white-space:nowrap;
  opacity:.999;               /* keeps the glyphs on their own layer */
}
/* The word arriving is the one being read, so the ones above and below it
   are dimmed rather than fully drawn. */
.cyc__list i{ transition:opacity .4s ease-out }
.cyc__list i[data-off]{ opacity:0 }

@media (prefers-reduced-motion:reduce){
  /* No motion at all: the first word stays, the rest are never shown.
     A cycling headline is decoration; the headline is not. */
  .cyc__win{ width:auto !important; transition:none }
  .cyc__list{ transform:none !important; transition:none }
  .cyc__list i:not(:first-child){ display:none }
}

/* ---- short screens ----------------------------------------------------
   On a 320x568 phone the hero CTA landed at 778px: 210px below the fold.
   The headline and the lede were sized for a 390px-wide screen without
   asking how TALL it is, and an iPhone SE is short before it is narrow.
   Height is the constraint here, so the query asks about height. */
@media (max-height:680px) and (max-width:520px){
  header.hero{ min-height:0 }
  /* The top padding stays generous enough to clear the fixed header; the
     savings come from the gaps between the hero's own parts instead. */
  /* The header is 114px tall at 320px because the row wraps, so 5.4rem of
     padding put the eyebrow UNDERNEATH it. Clearance comes first. */
  .hero__inner{ padding:8.2rem 1.3rem 2rem }
  .hero .mono{ margin-bottom:.7rem; font-size:.56rem }
  h1{ font-size:clamp(1.8rem,1rem + 4.4vw,2.05rem) }
  body{ font-size:15px }
  /* The real cause was the copy, not the spacing. The hero lede runs 45
     words, more than twice what a hero should carry, and on a 568px-tall
     screen it is the whole reason the button fell off. The promise stays;
     the detail is one scroll away and repeated in the section below. */
  .lede-more{ display:none }
  .hero .lede{ font-size:1.04rem; line-height:1.45; margin-bottom:1.1rem }
  .cta-row{ margin-bottom:.55rem; gap:.55rem }
  .micro{ font-size:.74rem; line-height:1.45 }
}
/* Narrow AND short: the second CTA drops under the first rather than
   squeezing both onto one line. */
@media (max-height:680px) and (max-width:400px){
  .cta-row{ flex-direction:column; align-items:stretch }
  .cta-row .btn{ width:100%; justify-content:center }
}

/* ==========================================================================
   THE PARTICLE FIELD  (see assets/empire-field.js)

   A drifting rainbow field that reacts to the pointer, used behind the
   Empire Assist section and on its page. The canvas sits BEHIND the
   content rather than over it — a decorative layer that intercepts
   clicks is a decorative layer that breaks the page.
   ========================================================================== */
.ef-wrap{position:relative;isolation:isolate;overflow:hidden}
.ef-canvas{position:absolute;inset:0;z-index:-2;pointer-events:none;display:block}
/* A scrim between the field and the words. The field is deliberately
   busy; text over an unscrimmed particle wash is unreadable, and no
   amount of it being pretty makes up for that. */
.ef-wrap::after{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:radial-gradient(125% 95% at 50% 45%, rgba(8,11,9,.42), rgba(8,11,9,.72) 62%, rgba(8,11,9,.88))}
/* :not(.ef-canvas) is load-bearing, not tidiness.
   The canvas is inserted as the section's FIRST CHILD, so it matches
   ".ef-wrap > *" too. That selector and ".ef-canvas" are both a single
   class, so they have identical specificity and the one written later
   wins — which was this one. The canvas lost its position:absolute,
   became an in-flow block at its full height, and pushed the entire
   section's text down below itself. The symptom looked like "the field
   is in its own separate section", and the cause was one selector being
   four lines further down the file. */
.ef-wrap > *:not(.ef-canvas){position:relative;z-index:1}

/* The rainbow rule and gradient wordmark, shared with Empire Assist. */
.ef-rainbow{
  background:linear-gradient(90deg,#ff5f6d 0%,#ffb347 16%,#ffe259 32%,#3ecf8e 50%,#4facfe 66%,#a76bff 83%,#ff5f6d 100%);
  background-size:200% 100%;animation:ef-flow 9s linear infinite}
@keyframes ef-flow{from{background-position:0% 50%}to{background-position:200% 50%}}
.ef-word{-webkit-background-clip:text;background-clip:text;color:transparent}
.ef-rule{height:2px;border-radius:2px;margin:0 0 1.4rem;max-width:6rem}

@media (prefers-reduced-motion:reduce){
  .ef-rainbow{animation:none}
}
