/* Shared styles for the public pages: /pricing, /terms, /privacy.
   Lifted out of pricing.html so the three cannot drift apart. */
  /* Same palette as the app itself (styles.css), so the public site and the
     product do not look like two different companies. */
  /* `hidden` has to actually hide.
     The browser's own rule is `[hidden] { display: none }`, which any class
     setting a display beats — `.calc-better { display: flex }`, `.promo-strip`,
     `.btn`, `.mock`, `.ticker` all did. The visible symptoms were a plan offer
     that went on recommending a plan the sliders had moved past, an empty
     green discount bar with no discount running, and a Pay button on a page
     that cannot take payment. `!important` is right here and almost nowhere
     else: it also beats the inline `display` a couple of these carry, and
     nothing should ever want to show an element marked hidden. */
  [hidden] { display: none !important; }

  :root {
    --ink: #eef5f1;
    --muted: #8aa298;
    --line: #26322c;
    --bg: #070b09;
    --soft: #0e1613;
    --card: #141d19;
    --brand: #34d399;
    --brand-dark: #10b981;
    --accent: #22d3ee;
    --ok: #34d399;
    --radius: 14px;
    /* A hairline of light along the top of a raised surface. One line, and it
       is most of why a panel reads as a physical object rather than a box. */
    --edge: inset 0 1px 0 rgba(255,255,255,.055);
    --shadow-1: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.28);
    --shadow-2: 0 2px 4px rgba(0,0,0,.4), 0 18px 50px rgba(0,0,0,.45);
    /* Slow and certain. Nothing on the page overshoots or bounces — confidence
       reads as calm, and a wobble reads as a toy. */
    --ease: cubic-bezier(.22,.61,.36,1);
  }
  * { box-sizing: border-box; }
  body {
    margin: 0;
    /* SF Pro on Apple devices, Segoe UI Variable on Windows 11, Inter where it
       is installed. No web font is downloaded: the system one is already the
       most carefully drawn face on the machine, and it renders instantly. */
    font: 16px/1.65 -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI Variable Text",
          "Segoe UI", Inter, Roboto, Helvetica, Arial, sans-serif;
    color: var(--ink);
    /* Not flat black — a slow wash of green towards the top, so the page has a
       light source and the sections below settle into shadow. */
    background:
      radial-gradient(1200px 600px at 50% -10%, rgba(52,211,153,.05), transparent 70%),
      var(--bg);
    background-attachment: fixed;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
  }
  /* Figures line up in a column and stop jittering as a slider moves. */
  .price, .calc-row output, td.num, #calcTotal { font-variant-numeric: tabular-nums; }
  .wrap { max-width: 1040px; margin: 0 auto; padding: 0 20px; }
  header.hero {
    background: radial-gradient(120% 140% at 15% 0%, #16241d 0%, var(--bg) 60%);
    color: var(--ink);
    border-bottom: 1px solid var(--line);
    padding: 64px 0 72px;
  }
  /* Display type: bigger, tighter and heavier. Letter-spacing has to come IN as
     type gets larger — the spacing that suits body text looks loose and cheap
     at headline size, and this one change does more for the feel of a page
     than any amount of colour. */
  header.hero h1 {
    font-size: clamp(2.1rem, 4.6vw, 3.4rem); margin: 0 0 16px; line-height: 1.08;
    letter-spacing: -.028em; font-weight: 700;
    font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI Variable Display",
                 "Segoe UI", Inter, Roboto, Helvetica, Arial, sans-serif;
  }
  header.hero p {
    font-size: 1.12rem; color: var(--muted); margin: 0 0 30px;
    /* Around 68 characters. Longer lines and the eye loses its place coming
       back to the left edge; this is the single biggest readability lever. */
    max-width: 58ch; line-height: 1.6;
  }
  /* The header floats: it rides over the page as you scroll, on frosted glass
     so the content reads through it, and the logo is always one click from
     home. Sticky rather than fixed, so it still sits inside the hero's
     padding at the top of the page instead of covering it. */
  .topbar {
    /* Fixed, not sticky: sticky only holds inside its own parent, so the bar
       rode away the moment the hero scrolled past. Fixed keeps it over the
       whole page, which is the point of putting the logo there. */
    position: fixed; top: 12px; left: 50%; transform: translateX(-50%);
    width: min(1040px, calc(100% - 32px)); z-index: 40;
    display: flex; justify-content: space-between; align-items: center; gap: 20px;
    padding: 10px 14px;
    border: 1px solid transparent; border-radius: 16px;
    transition: background .35s var(--ease), border-color .35s var(--ease),
                box-shadow .35s var(--ease), transform .35s var(--ease), opacity .35s var(--ease);
  }
  /* The bar no longer takes up space in the flow, so the hero makes room for
     it. !important because the legal pages set their padding inline, and an
     inline style is the one thing a stylesheet cannot otherwise reach. */
  header.hero { padding-top: 104px !important; }
  /* Only once it has lifted off the top of the page — a bar that is already
     frosted while sitting still looks like a mistake. */
  /* Out of the way while reading down the page; back the moment you scroll
     up. pointer-events off as well, or the invisible bar still swallows
     clicks meant for the page underneath. */
  .topbar.gone {
    transform: translateX(-50%) translateY(-150%);
    opacity: 0; pointer-events: none;
  }
  .topbar.floating {
    background: rgba(10,16,13,.72);
    -webkit-backdrop-filter: blur(16px) saturate(140%); backdrop-filter: blur(16px) saturate(140%);
    border-color: rgba(255,255,255,.07);
    box-shadow: var(--edge), 0 10px 30px rgba(0,0,0,.35);
  }
  /* Two selectors, not one, and this is why: `header.hero p` further down sets
     `margin: 0 0 30px`, and one element plus one class beats one class. So the
     `auto` side margins here were being thrown away and the line sat against
     the left edge, centred text inside a left-hung box. */
  .partner-line,
  header.hero p.partner-line {
    font-size: .84rem; color: var(--muted);
    margin: 36px auto 0; padding: 10px 16px 0;
    border-top: 1px solid var(--line);
    /* Centred as a block as well as centred text, or a short line sits
       against the left edge of a very wide page. */
    text-align: center; max-width: 72ch;
  }

  /* The discount, announced once at the top. Only rendered while one is
     actually running, and it is a link, because a banner that cannot be
     acted on is just something in the way. */
  .promo-strip {
    display: block; margin: 0 0 24px; padding: 11px 18px;
    border-radius: 12px; text-decoration: none; text-align: center;
    font-size: .88rem; font-weight: 600; color: #03231a;
    background: linear-gradient(90deg, #3ee0a6, var(--brand) 55%, var(--accent));
    box-shadow: inset 0 1px 0 rgba(255,255,255,.4), 0 10px 26px rgba(16,185,129,.18);
    transition: transform .3s var(--ease), box-shadow .3s var(--ease);
  }
  .promo-strip:hover { transform: translateY(-1px); box-shadow: inset 0 1px 0 rgba(255,255,255,.5), 0 14px 32px rgba(16,185,129,.26); }
  .promo-strip b { font-weight: 800; }
  .usage-line {
    text-align: center; font-size: .86rem; color: var(--muted);
    margin: 26px auto 0; padding-top: 18px; border-top: 1px solid var(--line);
    font-variant-numeric: tabular-nums;
  }
  .partner-line a { color: var(--brand); text-decoration: none; font-weight: 600; }
  .partner-line a:hover { text-decoration: underline; }
  .brand img { transition: transform .4s var(--ease); }
  .brand a:hover img { transform: translateY(-2px) rotate(-4deg); }
  /* Eight links on the pricing page now, so the gap is tighter and the row
     is allowed to wrap rather than squeezing the logo and the buttons
     either side of it. */
  .nav { display: flex; gap: 20px; margin-left: auto; flex-wrap: wrap; justify-content: center; }
  .nav a { color: var(--muted); text-decoration: none; font-size: .92rem; font-weight: 500; }
  .nav a:hover { color: var(--ink); }
  /* Anchored sections must not slide under the heading when jumped to. */
  section[id] { scroll-margin-top: 20px; }
  /* The nav used to be hidden outright below 720px, which left a phone with no
     way to reach Pricing or anything else — only Log in. It now wraps onto its
     own line under the brand instead of disappearing. */
  @media (max-width: 720px) {
    /* On a phone the bar wraps onto two rows, so it is too tall to float over
       the page without covering half of it. It goes back into the flow. */
    .topbar {
      position: static; transform: none; width: auto;
      flex-wrap: wrap; gap: 10px 14px; margin-bottom: 20px; padding: 0;
      background: none; border-color: transparent; box-shadow: none;
    }
    header.hero { padding-top: 28px !important; }
    /* `gap: 0` with `space-between` ran the links together into what read as
       one sentence — "What it does Infrastructure Pricing Websites" — with no
       sign any of it was tappable. They are pills now: spaced, bordered, and
       each one a target a thumb can actually hit. */
    .nav {
      order: 3; width: 100%; margin-left: 0; gap: 8px;
      justify-content: flex-start; flex-wrap: wrap;
      border-top: 1px solid var(--line); padding-top: 14px;
    }
    .nav a {
      font-size: .82rem; padding: 7px 13px; border-radius: 99px;
      border: 1px solid var(--line); background: rgba(255,255,255,.03);
      color: var(--ink);
    }
    /* The brand and the buttons share the top line; the buttons keep their
       own size rather than being stretched across it. */
    .topbar-actions { margin-left: auto; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
    .topbar-actions .btn, .topbar-actions .login {
      width: auto; padding: 9px 14px; font-size: .85rem; white-space: nowrap;
    }
  }
  .brand { font-weight: 700; letter-spacing: .02em; font-size: 1.05rem; }
  /* The mark, not the word. It links home from every page, which is the one
     navigation habit every visitor already has. */
  .brand a { display: inline-flex; align-items: center; gap: 10px; color: inherit; text-decoration: none; }
  .brand img { width: 34px; height: 34px; display: block; border-radius: 8px; }
  .brand .wordmark { font-weight: 700; letter-spacing: -.01em; }

  /* Buttons sitting next to each other have to share a baseline, or the
     filled one rides high and the pair looks broken. Same line box, same
     vertical padding, middle-aligned — the fix is boring and it is the thing
     that separates a page that looks finished from one that does not. */
  .btn, .login, .btn-sm {
    vertical-align: middle; line-height: 1.25; text-align: center;
  }
  /* The quiet one. Glass rather than an outline: it belongs to the page
     instead of sitting on top of it, which keeps the eye on the green. */
  .login {
    display: inline-block;
    color: var(--ink); text-decoration: none; font-size: 1rem; font-weight: 600;
    /* 13px + 1px border = the 14px the filled button pads to, so the two are
       exactly the same height. */
    border: 1px solid rgba(255,255,255,.1); padding: 13px 24px; border-radius: 12px;
    background: rgba(255,255,255,.035);
    -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
    box-shadow: var(--edge);
    transition: background .28s var(--ease), border-color .28s var(--ease), transform .28s var(--ease);
  }
  .login:hover { color: var(--ink); background: rgba(255,255,255,.07); border-color: rgba(255,255,255,.2); }

  /* The loud one. Two greens rather than one so the face is lit from above, a
     hairline highlight on the top edge, and a shadow tinted with the button's
     own colour instead of black — that last one is the difference between a
     button that sits ON the page and one that floats above it. */
  .btn {
    position: relative; overflow: hidden;
    display: inline-block; text-decoration: none; cursor: pointer; border: 0;
    background: linear-gradient(180deg, #3ee0a6 0%, var(--brand) 45%, var(--brand-dark) 100%);
    color: #03231a; font-weight: 650; font-size: 1rem; letter-spacing: -.01em;
    padding: 14px 28px; border-radius: 12px;
    box-shadow: inset 0 1px 0 rgba(255,255,255,.45), 0 1px 2px rgba(0,0,0,.35),
                0 10px 26px rgba(16,185,129,.22);
    transition: transform .28s var(--ease), box-shadow .28s var(--ease), filter .28s var(--ease);
  }
  /* The reflection. A band of light that lives off the left edge and sweeps
     across the face on hover — the same trick a glass surface plays when you
     tilt it, which is why it reads as a material rather than an effect. */
  .btn::after {
    /* Above the face, including the label — light falls on the whole surface,
       and a highlight that stopped at the text would give the game away.
       It must NOT be given a negative z-index: that paints it behind the
       button's own gradient, where nothing can be seen of it. */
    content: ''; position: absolute; inset: 0; pointer-events: none;
    background: linear-gradient(105deg, transparent 35%, rgba(255,255,255,.45) 50%, transparent 65%);
    transform: translateX(-120%);
    transition: transform .7s var(--ease);
  }
  .btn:hover::after { transform: translateX(120%); }
  .btn:hover {
    filter: brightness(1.04);
    transform: translateY(-2px);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.5), 0 2px 4px rgba(0,0,0,.35),
                0 16px 38px rgba(16,185,129,.3);
  }
  /* Pressed. A button that gives slightly under the finger is the whole of
     why an interface feels physical, and it costs one line. */
  .btn:active { transform: translateY(0) scale(.985); transition-duration: .08s; }
  .btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
  .btn[disabled] { opacity: .55; cursor: default; filter: grayscale(.3); }
  .btn[disabled]:hover { transform: none; }
  /* Hierarchy without changing size: the paid action is the filled green one,
     everything beside it is glass. One weight of button, so nothing on the
     page shouts. */
  section { padding: 56px 0; }
  section.alt { background: var(--soft); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
  h2 {
    font-size: clamp(1.6rem, 2.6vw, 2.05rem); margin: 0 0 10px; line-height: 1.15;
    letter-spacing: -.022em; font-weight: 700;
    font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI Variable Display",
                 "Segoe UI", Inter, Roboto, Helvetica, Arial, sans-serif;
  }
  .lede { color: var(--muted); margin: 0 0 34px; max-width: 62ch; font-size: 1.02rem; }
  .cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 20px; }
  .card {
    position: relative;
    border: 1px solid var(--line); border-radius: var(--radius); padding: 26px;
    /* A panel lit from above rather than a flat fill. */
    background: linear-gradient(180deg, rgba(255,255,255,.028), rgba(255,255,255,0) 40%), var(--card);
    box-shadow: var(--edge), var(--shadow-1);
    display: flex; flex-direction: column;
  }
  .card h3 { margin: 0 0 4px; font-size: 1.12rem; letter-spacing: -.012em; }
  .card .units { color: var(--muted); font-size: .93rem; margin-bottom: 14px; }
  .card .price { font-size: 2.1rem; font-weight: 700; line-height: 1; letter-spacing: -.028em; }
  .card .feat { margin: 0; font-size: .93rem; color: var(--muted); }
  .card .per { color: var(--muted); font-size: .88rem; margin-top: 8px; }
  table { width: 100%; border-collapse: collapse; background: var(--card); }
  .tablewrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius); }
  th, td { text-align: left; padding: 14px 18px; border-bottom: 1px solid var(--line); }
  th { font-size: .8rem; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); font-weight: 600; }
  tr:last-child td { border-bottom: 0; }
  td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
  th.num { text-align: right; }
  .note { color: var(--muted); font-size: .9rem; margin-top: 14px; }
  .shotgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 18px; }
  .shot { margin: 0; }
  .shot img {
    width: 100%; display: block; border: 1px solid var(--line);
    border-radius: var(--radius); background: var(--card);
  }
  .shot figcaption { color: var(--muted); font-size: .88rem; margin-top: 10px; }
  ol.steps { counter-reset: s; list-style: none; padding: 0; margin: 0; display: grid; gap: 20px; }
  ol.steps li { counter-increment: s; padding-left: 52px; position: relative; }
  ol.steps li::before {
    content: counter(s); position: absolute; left: 0; top: -2px;
    width: 34px; height: 34px; border-radius: 50%; background: var(--brand); color: #06231a;
    display: grid; place-items: center; font-weight: 700;
  }
  ol.steps strong { display: block; }
  form { display: grid; gap: 16px; max-width: 560px; }
  .row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
  label { display: block; font-weight: 600; font-size: .9rem; margin-bottom: 6px; }
  input, select, textarea {
    width: 100%; padding: 11px 13px; border: 1px solid var(--line); border-radius: 8px;
    font: inherit; color: var(--ink); background: #0d1310;
  }
  input:focus, select:focus, textarea:focus { outline: 2px solid var(--brand); border-color: var(--brand); }
  textarea { min-height: 96px; resize: vertical; }
  /* A file input left to the browser is a grey system button on a dark panel.
     The button half is styled on its own; the field keeps the same frame as
     every other input so the form still reads as one thing. */
  input[type="file"] { padding: 9px 11px; cursor: pointer; }
  input[type="file"]::file-selector-button {
    font: inherit; font-weight: 600; margin-right: 12px; cursor: pointer;
    padding: 7px 14px; border-radius: 8px; border: 1px solid var(--line);
    background: var(--card); color: var(--ink);
  }
  input[type="file"]::file-selector-button:hover { border-color: var(--brand); color: var(--brand); }
  .hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
  .consent {
    border: 1px solid var(--line); border-radius: var(--radius);
    padding: 16px 18px; background: var(--card);
  }
  .consent .tick { display: flex; gap: 10px; align-items: flex-start; margin: 0 0 10px; cursor: pointer; }
  .consent .tick input { width: auto; margin: 3px 0 0; flex: 0 0 auto; }
  .consent .tick span { font-weight: 600; font-size: .93rem; }
  .consent p { margin: 0; font-size: .82rem; line-height: 1.55; color: var(--muted); }
  .consent a { color: var(--brand); }
  /* The same tick outside a .consent box — the one above the calculator's Pay
     button. It was taking the browser's default link blue, which is the one
     colour on the page that belongs to nothing. */
  .tick a { color: var(--brand); text-decoration: underline; text-underline-offset: 2px; }
  .tick a:hover { color: var(--ink); }
  .msg { padding: 14px 16px; border-radius: 8px; font-size: .95rem; }
  .msg.err { background: rgba(248,113,113,.1); color: #f87171; border: 1px solid rgba(248,113,113,.35); }
  .msg.ok { background: rgba(52,211,153,.1); color: var(--ok); border: 1px solid rgba(52,211,153,.35); }
  footer { padding: 36px 0; color: var(--muted); font-size: .9rem; border-top: 1px solid var(--line); }
  @media (max-width: 560px) { .row { grid-template-columns: 1fr; } section { padding: 40px 0; } }

  /* ---- Demo video and product screenshots ---- */
  .hero-video {
    width: 100%; display: block; border-radius: var(--radius);
    border: 1px solid var(--line); background: #000;
    box-shadow: var(--edge), var(--shadow-2);
  }

  /* Laid out like the product: a menu column beside a window. The menu is
     real — pressing an item changes the screen, and so does pressing the
     screen — because a picture of software people can poke at reads as
     software, and a static picture reads as a brochure. */
  /* As wide as the screen allows, because the whole point of it is to be
     readable. A dashboard shrunk to 800px is a picture of a dashboard; at
     full width it is the thing itself. The 1600px ceiling is where a
     1360-wide screenshot stops gaining anything from being stretched. */
  .shotshow {
    max-width: min(1600px, 100%); margin: 0 auto; text-align: left;
    display: block;
    border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
    background: var(--card); box-shadow: var(--edge), var(--shadow-2);
  }
  /* A row of pills above the window. Wraps on a narrow screen, and with a
     single screenshot there is nothing to choose between, so it collapses to
     nothing rather than showing one lonely tab. */
  .shotshow-tabs {
    display: flex; flex-wrap: wrap; justify-content: center;
    gap: 6px; margin: 0 auto 14px;
  }
  .shotshow-tabs:has(> :only-child) { display: none; }
  .shotshow-tab {
    font: inherit; font-size: .82rem; font-weight: 600; cursor: pointer; text-align: center;
    color: var(--muted); background: none; border: 1px solid var(--line);
    border-radius: 99px; padding: 7px 15px;
    transition: color .25s var(--ease), background .25s var(--ease), border-color .25s var(--ease);
  }
  .shotshow-tab:hover { color: var(--ink); background: rgba(255,255,255,.04); }
  .shotshow-tab.on {
    color: var(--brand); background: rgba(52,211,153,.1);
    border-color: rgba(52,211,153,.28);
  }
  .shotshow-frame { min-width: 0; }
  .shotshow-bar {
    display: flex; align-items: center; gap: 7px;
    padding: 11px 14px; border-bottom: 1px solid var(--line);
    background: rgba(255,255,255,.02); font-size: .78rem; color: var(--muted);
  }
  .shotshow-bar i { width: 9px; height: 9px; border-radius: 50%; background: var(--line); }
  .shotshow-bar span { margin-left: 8px; }
  /* The screen is a button, so it is reachable by keyboard as well as mouse,
     and it says so on hover rather than being a secret. */
  .shotshow-screen { display: block; width: 100%; padding: 0; border: 0; background: none; cursor: pointer; }
  .shotshow-screen img { display: block; width: 100%; height: auto; }
  /* This one section is allowed out past the page's own 1040px column. The
     screenshot is the content here, not an illustration beside it. */
  #inside > .wrap { max-width: 1640px; }
  .shotshow-screen[disabled] { cursor: default; }
  .shotshow-screen:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
  /* On a phone a 1360px-wide dashboard is unreadable however it is scaled, so
     it is not scaled: the window scrolls sideways and the picture keeps its
     real size, which is the one way the figures on it stay legible. */
  @media (max-width: 760px) {
    .shotshow-frame { overflow-x: auto; -webkit-overflow-scrolling: touch; }
    .shotshow-screen { width: auto; }
    .shotshow-screen img { max-width: none; width: 900px; }
    .shotshow-bar { position: sticky; left: 0; }
    .shotshow-tab { font-size: .76rem; padding: 6px 12px; }
  }

  /* ---- Motion ----
     Everything below is decoration. The page is fully readable with all of it
     switched off, which is exactly what happens for anyone who has asked their
     system to reduce motion, and for anyone whose JavaScript never runs. */
  .cards .card, .shot img, .tablewrap {
    transition: transform .4s var(--ease), border-color .4s var(--ease), box-shadow .4s var(--ease);
  }
  .cards .card:hover, .shot img:hover {
    transform: translateY(-3px);
    border-color: rgba(52,211,153,.4);
    box-shadow: var(--edge), var(--shadow-2), 0 0 0 1px rgba(52,211,153,.09);
  }
  tbody tr { transition: background .18s ease; }
  tbody tr:hover { background: rgba(52,211,153,.05); }
  /* No `both` fill: with it, the element holds opacity 0 until the animation
     runs, so anything that stops it running — a battery saver, a paused tab,
     an old browser — leaves the headline and the main button permanently
     invisible. Without it the natural state is visible and the animation is
     pure decoration on top. */
  header.hero h1, header.hero p, header.hero .btn { animation: rise .7s cubic-bezier(.22,.7,.3,1) forwards; }
  header.hero p { animation-delay: .09s; }
  header.hero .btn { animation-delay: .18s; }
  @keyframes rise { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
  html { scroll-behavior: smooth; }
  @media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    header.hero h1, header.hero p, header.hero .btn { animation: none; }
    .cards .card:hover, .shot img:hover, .btn:hover, .btn:active { transform: none; }
    /* The sweep is the one piece of decoration that moves on its own, so it
       is the first thing to go when someone has asked for less of it. */
    .btn::after { display: none; }
  }

/* ---- Legal pages (/terms, /privacy) ---- */
.legal { max-width: 780px; }
.legal h2 { margin: 34px 0 10px; font-size: 1.15rem; }
.legal h2:first-of-type { margin-top: 0; }
.legal p, .legal li { color: var(--muted); }
.legal li { margin-bottom: 8px; }
.legal strong { color: var(--ink); }
.legal .updated { font-size: .85rem; color: var(--text-dim, #4a6358); margin-bottom: 28px; }
.legal .callout {
  border: 1px solid var(--line); border-left: 3px solid var(--brand);
  border-radius: var(--radius); padding: 16px 18px; background: var(--card); margin: 22px 0;
}
.legal .callout p { margin: 0; }
footer .foot-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 24px; margin-bottom: 24px;
}
footer .foot-grid strong { color: var(--ink); display: block; margin-bottom: 8px; }
footer a { color: var(--muted); text-decoration: none; display: block; margin-bottom: 6px; }
footer a:hover { color: var(--brand); }
footer .foot-legal { border-top: 1px solid var(--line); padding-top: 20px; font-size: .84rem; }

.hint { margin: .35rem 0 0; font-size: .75rem; color: var(--muted); }

/* ── Landing page (/) ─────────────────────────────────────────────── */
.eyebrow {
  display: inline-block; font-size: .78rem; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--brand);
  border: 1px solid rgba(52, 211, 153, .35); border-radius: 100px;
  padding: 5px 14px; margin-bottom: 18px;
}
.hero-note { font-size: .85rem; color: var(--muted); margin-top: 20px; }

/* The comparison table. Scrolls inside its own box on a phone rather than
   forcing the whole page sideways. */
.compare { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.compare table {
  width: 100%; min-width: 640px; border-collapse: collapse;
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
}
.compare th, .compare td {
  text-align: left; padding: 14px 18px; border-bottom: 1px solid var(--line);
  font-size: .92rem; vertical-align: top;
}
.compare thead th {
  background: var(--card); color: var(--ink); font-size: .8rem;
  text-transform: uppercase; letter-spacing: .05em;
}
.compare thead th:last-child { color: var(--brand); }
.compare tbody td:first-child { color: var(--ink); font-weight: 600; width: 26%; }
.compare tbody td:nth-child(2) { color: var(--muted); }
.compare tbody td:last-child { color: var(--ink); }
.compare tbody tr:last-child td { border-bottom: 0; }
.compare tbody tr:hover td { background: rgba(52, 211, 153, .04); }
.compare-note {
  font-size: .82rem; color: var(--muted); margin: 16px 0 0;
  border-left: 2px solid var(--line); padding-left: 14px; max-width: 720px;
}
.fineprint {
  font-size: .74rem; color: var(--muted); margin: 28px 0 0;
  padding-top: 18px; border-top: 1px solid var(--line);
}

/* ── Phones ───────────────────────────────────────────────────────────
   The public pages were laid out for a desktop and merely survived a phone.
   Most visitors arrive on one, so the spacing, type and tap targets are set
   deliberately here rather than left to shrink.                          */
.topbar-actions { display: flex; gap: 8px; align-items: center; margin-left: auto; }
.btn-sm { padding: 10px 18px; font-size: .92rem; border-radius: 10px; }

/* Pricing calculator. Label, slider and the figure it is currently on, so the
   number being dragged is readable without looking away from the thumb. */
.calc-row { display: grid; grid-template-columns: 180px 1fr 90px; gap: 14px; align-items: center; margin-bottom: 14px; }
.calc-row label { font-size: .9rem; color: var(--muted); }
.calc-row input[type="range"] { width: 100%; accent-color: var(--brand); }
.calc-row output { font-variant-numeric: tabular-nums; font-weight: 700; text-align: right; }
#calcLines td { padding: 5px 0; border-bottom: 1px solid var(--line); }
#calcLines td:last-child { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
#calcLines .calc-detail { color: var(--muted); font-size: .78rem; }
/* The cheaper plan, offered beside the built one. Lit, because it is the
   better deal and hiding that would be the expensive kind of quiet. */
.calc-better {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap; justify-content: space-between;
  margin-top: 16px; padding: 14px 16px; border-radius: 12px;
  background: linear-gradient(180deg, rgba(52,211,153,.09), rgba(52,211,153,.03));
  border: 1px solid rgba(52,211,153,.3);
}
.calc-better strong { display: block; font-size: .95rem; }
.calc-better span { font-size: .8rem; color: var(--muted); }
@media (max-width: 720px) {
  .calc-row { grid-template-columns: 1fr 70px; }
  .calc-row label { grid-column: 1 / -1; margin-bottom: -6px; }
}

@media (max-width: 720px) {
  header.hero { padding: 28px 0 40px; }
  header.hero h1 { font-size: 1.75rem; line-height: 1.25; }
  header.hero p { font-size: 1rem; margin-bottom: 22px; }
  .hero-note { margin-top: 16px; }
  section { padding: 36px 0; }
  h2 { font-size: 1.35rem; }
  .lede { font-size: .95rem; margin-bottom: 22px; }
  .card { padding: 18px; }
  .cards { gap: 12px; }
  .eyebrow { font-size: .68rem; padding: 4px 11px; margin-bottom: 14px; }

  /* Full-width buttons on a phone: a thumb is wider than a mouse pointer, and
     two buttons squeezed side by side is how people mis-tap. */
  header.hero .btn,
  header.hero .hero-copy .login,
  header.hero > .wrap > .login,
  #cta .btn, #cta .login {
    display: block; width: 100%; text-align: center; margin: 0 0 10px;
    padding: 14px 20px;
  }
  .topbar-actions .btn, .topbar-actions .login {
    display: inline-block; width: auto; margin: 0; padding: 8px 14px; font-size: .85rem;
  }

  /* The comparison table cannot shrink below readable, so it scrolls sideways
     inside its own box — with a visible edge so people know it does. */
  .compare {
    border: 1px solid var(--line); border-radius: var(--radius);
    background:
      linear-gradient(to right, var(--soft) 30%, rgba(17, 25, 22, 0)) left / 40px 100% no-repeat,
      linear-gradient(to left, var(--soft) 30%, rgba(17, 25, 22, 0)) right / 40px 100% no-repeat;
  }
  .compare table { border: 0; min-width: 560px; }
  .compare th, .compare td { padding: 11px 13px; font-size: .84rem; }
  .compare tbody td:first-child { width: 30%; }

  .foot-grid { gap: 22px; }
  footer .foot-grid a { padding: 3px 0; display: block; }
}

/* Very small phones. */
@media (max-width: 380px) {
  header.hero h1 { font-size: 1.55rem; }
  .nav a { font-size: .8rem; }
  .topbar-actions .btn, .topbar-actions .login { padding: 7px 11px; font-size: .8rem; }
}

/* "Log in" broke onto two lines once the bar got tight. */
.login, .btn { white-space: nowrap; }

@media (max-width: 720px) {
  /* The hero's second button carries an inline left margin for the desktop
     layout, which fights the stacked one here. Inline styles win on
     specificity, so this needs !important to undo it. */
  header.hero > .wrap > .login[style] { margin-left: 0 !important; }
}

/* ── Landing page, alive (v9) ─────────────────────────────────────── */
header.hero { position: relative; overflow: hidden; }
header.hero::before {
  content: ""; position: absolute; inset: -30% -10% auto auto; width: 620px; height: 620px;
  background: radial-gradient(circle, rgba(52,211,153,.18), transparent 65%);
  filter: blur(10px); animation: drift 14s ease-in-out infinite alternate; pointer-events: none;
}
header.hero .wrap { position: relative; }
@keyframes drift { from { transform: translate(0,0); } to { transform: translate(-120px, 90px); } }
.hero-grid { display: grid; grid-template-columns: 1.1fr .9fr; gap: 40px; align-items: center; }
.grad { background: linear-gradient(90deg, #34d399, #22d3ee); -webkit-background-clip: text; background-clip: text; color: transparent; }
.live-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--brand); margin-right: 8px; vertical-align: middle; animation: pulse 1.8s infinite; }
@keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(52,211,153,.6); } 100% { box-shadow: 0 0 0 10px rgba(52,211,153,0); } }

/* Product illustration */
.mock {
  background: var(--card); border: 1px solid var(--line); border-radius: 16px; padding: 14px;
  box-shadow: 0 30px 80px rgba(0,0,0,.5), 0 0 0 1px rgba(52,211,153,.06);
  animation: float 6s ease-in-out infinite; max-width: 100%;
}
@keyframes float { 50% { transform: translateY(-8px); } }
.mock-bar { display: flex; align-items: center; gap: 6px; font-size: .75rem; color: var(--muted); margin-bottom: 12px; }
.mock-bar i { width: 9px; height: 9px; border-radius: 50%; background: var(--line); }
.mock-bar span { margin-left: 8px; }
.mock-lead { display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 10px; background: var(--soft); }
.mock-lead strong { display: block; font-size: .85rem; }
.mock-lead small { color: var(--muted); font-size: .72rem; }
.mock-avatar { width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center; background: linear-gradient(135deg,#34d399,#22d3ee); color: #06231a; font-weight: 700; }
.mock-dispo { margin-left: auto; font-size: .68rem; font-weight: 700; padding: 3px 9px; border-radius: 99px; color: #fbbf24; background: rgba(251,191,36,.12); opacity: 0; animation: loop-show 12s infinite; animation-delay: 0s; }
.mock-thread { display: flex; flex-direction: column; gap: 8px; padding: 14px 4px; min-height: 190px; }
.bub { max-width: 82%; padding: 8px 12px; border-radius: 14px; font-size: .8rem; line-height: 1.4; opacity: 0; animation: loop-bubble 12s infinite; }
.bub.out { align-self: flex-end; background: rgba(52,211,153,.16); border-bottom-right-radius: 4px; }
.bub.in { align-self: flex-start; background: var(--soft); border: 1px solid var(--line); border-bottom-left-radius: 4px; }
.b1 { animation-delay: .3s; } .b2 { animation-delay: 1.6s; } .b3 { animation-delay: 2.9s; } .b4 { animation-delay: 4.2s; }
.mock-call, .mock-note { font-size: .78rem; padding: 9px 12px; border-radius: 10px; margin-top: 6px; opacity: 0; animation: loop-bubble 12s infinite; }
.mock-call { background: rgba(34,211,238,.1); color: #67e8f9; animation-delay: 5.5s; display: flex; align-items: center; gap: 9px; }
.mock-note { background: var(--soft); color: var(--muted); animation-delay: 7s; }
.mock-dispo { animation-name: loop-bubble; animation-delay: 6.2s; }
.ring { width: 9px; height: 9px; border-radius: 50%; background: #22d3ee; animation: pulse-c 1.2s infinite; }
@keyframes pulse-c { 0% { box-shadow: 0 0 0 0 rgba(34,211,238,.7); } 100% { box-shadow: 0 0 0 10px rgba(34,211,238,0); } }
/* Each piece appears at its own delay, holds, and the whole scene fades together near the end of the 12s loop. */
@keyframes loop-bubble {
  0% { opacity: 0; transform: translateY(8px); }
  4% { opacity: 1; transform: none; }
  60% { opacity: 1; }
  66%, 100% { opacity: 0; }
}

/* Feature ticker */
.ticker { margin-top: 44px; overflow: hidden; mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent); -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent); }
.ticker-track { display: flex; gap: 12px; width: max-content; animation: ticker 38s linear infinite; }
.ticker-track span { font-size: .8rem; color: var(--muted); border: 1px solid var(--line); border-radius: 99px; padding: 6px 14px; white-space: nowrap; background: rgba(22,31,27,.6); }
@keyframes ticker { to { transform: translateX(-50%); } }

/* Stats band */
.stats { padding: 36px 0; border-bottom: 1px solid var(--line); }
.stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
.stat { text-align: left; }
.stat b { display: block; font-size: 2.6rem; line-height: 1; font-variant-numeric: tabular-nums; background: linear-gradient(90deg,#34d399,#22d3ee); -webkit-background-clip: text; background-clip: text; color: transparent; }
.stat span { display: block; color: var(--muted); font-size: .86rem; margin-top: 8px; }

/* How a lead moves */
/* With the illustration beside them, the five steps stack into a column and
   the whole process — the words and the thing happening — is one picture. */
/* Steps on the left, one screen on the right that plays whichever step is in
   the middle of the view. The screen is sticky, so it holds still while the
   list scrolls past it. */
.flow-grid { display: grid; grid-template-columns: .92fr 1.08fr; gap: 46px; align-items: start; margin-top: 26px; }
.flow { list-style: none; padding: 0; margin: 0; display: grid; gap: 12px; position: relative; }
.flow li {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 16px 18px 16px 58px; font-size: .88rem; color: var(--muted); position: relative;
  /* Each step needs enough height that scrolling actually moves through them.
     Compact cards all fitted on one screen, so the last two never crossed the
     middle of the view and the screen beside them never got past step three. */
  min-height: 23vh; display: flex; flex-direction: column; justify-content: center;
  cursor: pointer;
  /* Dimmed until it is the one being played, so the eye is told where it is
     in the sequence without a word being spent on it. */
  opacity: .5;
  transition: opacity .45s var(--ease), border-color .45s var(--ease), background .45s var(--ease), transform .45s var(--ease);
}
.flow li.on {
  opacity: 1; border-color: rgba(52,211,153,.4); transform: translateX(4px);
  background: linear-gradient(180deg, rgba(52,211,153,.06), rgba(255,255,255,0) 60%), var(--card);
}
/* The number is taken out of the text flow. NOT a grid on the li: the step's
   description is a bare text node, and a grid makes that its own item — it
   ends up in the 30px number column, one word per line. */
.flow li span {
  position: absolute; left: 16px; top: 15px;
  display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%;
  background: var(--line); color: var(--muted); font-weight: 700; font-size: .85rem;
  transition: background .45s var(--ease), color .45s var(--ease);
}
.flow li.on span { background: var(--brand); color: #06231a; }
.flow li strong { display: block; color: var(--ink); margin-bottom: 4px; }

.flow-stage { position: sticky; top: 104px; }
/* Each scene fades up as it takes over — a cut would read as a glitch. */
.fs-enter { animation: fs-in .42s var(--ease); }
@keyframes fs-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.fs-rows { display: grid; gap: 7px; padding: 4px 0; }
.fs-row {
  display: flex; align-items: center; gap: 10px; font-size: .82rem;
  padding: 9px 11px; border-radius: 9px; background: var(--soft); color: var(--ink);
}
.fs-row em { margin-left: auto; font-style: normal; color: var(--muted); font-size: .76rem; }
.fs-row.out { opacity: .45; text-decoration: line-through; }
.fs-tick { color: var(--brand); font-weight: 700; }
.fs-x { color: #f87171; font-weight: 700; }
.fs-head { font-size: .86rem; font-weight: 600; margin: 6px 0 12px; }
.fs-bar { height: 8px; border-radius: 99px; background: var(--soft); overflow: hidden; }
.fs-bar i { display: block; height: 100%; border-radius: 99px; background: linear-gradient(90deg, var(--brand), var(--accent)); }
.fs-split { display: flex; justify-content: space-between; font-size: .78rem; color: var(--muted); margin-top: 8px; }
.fs-chiprow { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 14px; }
.fs-chiprow span { font-size: .72rem; color: var(--muted); border: 1px solid var(--line); border-radius: 99px; padding: 4px 10px; }
.fs-thread { display: flex; flex-direction: column; gap: 8px; padding: 14px 2px 4px; }
/* These bubbles are placed by the script, so they must not inherit the
   looping reveal the hero illustration runs on. */
.fs-thread .bub { opacity: 1; animation: none; }
.fs-call { display: flex; align-items: center; gap: 9px; font-size: .8rem; color: #67e8f9; background: rgba(34,211,238,.1); padding: 10px 12px; border-radius: 10px; margin-top: 12px; }
.fs-wave { display: flex; align-items: flex-end; gap: 3px; height: 34px; margin-top: 12px; }
.fs-wave i { flex: 1; background: linear-gradient(180deg, var(--brand), rgba(52,211,153,.25)); border-radius: 2px; animation: fs-wave 1.1s ease-in-out infinite; }
.fs-wave i:nth-child(2n) { animation-delay: .15s; }
.fs-wave i:nth-child(3n) { animation-delay: .3s; }
.fs-wave i:nth-child(4n) { animation-delay: .45s; }
@keyframes fs-wave { 0%, 100% { height: 18%; } 50% { height: 100%; } }
.fs-cols { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; padding: 6px 0 2px; }
.fs-col { background: var(--soft); border-radius: 10px; padding: 10px 8px; }
.fs-col b { display: block; font-size: .68rem; color: var(--muted); font-weight: 600; margin-bottom: 8px; }
.fs-col i { display: block; height: 16px; border-radius: 5px; background: var(--line); margin-bottom: 6px; }
.fs-col.on { background: rgba(52,211,153,.08); box-shadow: inset 0 0 0 1px rgba(52,211,153,.3); }
.fs-col i.lit { background: linear-gradient(90deg, var(--brand), var(--accent)); }
.fs-note { font-size: .78rem; color: var(--muted); margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.fs-note.ok { color: var(--brand); }

@media (max-width: 860px) {
  /* No room to hold a screen still beside the text, so the steps go back to
     plain cards and the stage sits above them, played by its own order. */
  .flow-grid { grid-template-columns: 1fr; gap: 24px; }
  .flow-stage { position: static; order: -1; }
  .flow li { opacity: 1; transform: none; min-height: 0; display: block; cursor: default; }
  .flow li span { background: var(--brand); color: #06231a; }
}

/* Testimonials (only shown once real ones are added) */
.voices { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 18px; }
.voice { margin: 0; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 22px; }
.voice blockquote { margin: 0 0 14px; font-size: .98rem; }
.voice figcaption { color: var(--muted); font-size: .85rem; }
.voice figcaption strong { display: block; color: var(--ink); }
/* A face or a clip above the quote. Fixed height so a column of them lines
   up whatever shape the uploads are. */
.voice-media {
  display: block; width: 100%; height: 180px; object-fit: cover;
  border-radius: 10px; margin-bottom: 14px; background: var(--soft);
}
.stars { color: #fbbf24; font-size: 1rem; letter-spacing: 2px; margin-bottom: 10px; }
.stars .dim { color: var(--line); }
/* The star picker on the feedback form: radio buttons wearing stars, so it
   still works with a keyboard and still submits if the script never runs. */
.starpick { display: flex; gap: 4px; }
.starpick input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.starpick label {
  cursor: pointer; font-size: 1.6rem; line-height: 1; color: var(--line);
  margin: 0; transition: color .2s var(--ease), transform .2s var(--ease);
}
.starpick label:hover { transform: scale(1.12); }
.starpick input:checked ~ label { color: var(--line); }
.starpick label.lit { color: #fbbf24; }
.starpick input:focus-visible + label { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 4px; }

/* Scroll reveal — only when the script has switched motion on. */
.motion .reveal, .motion .cards .card, .motion .compare { opacity: 0; transform: translateY(22px); transition: opacity .6s ease, transform .6s cubic-bezier(.22,.7,.3,1), border-color .25s, box-shadow .25s; }
.motion .reveal.in, .motion .cards .card.in, .motion .compare.in { opacity: 1; transform: none; }

@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; }
  .flow { grid-template-columns: 1fr 1fr; }
  .stats-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
  .flow { grid-template-columns: 1fr; }
  .stat b { font-size: 2rem; }
  header.hero::before { width: 360px; height: 360px; }
}
@media (prefers-reduced-motion: reduce) {
  header.hero::before, .mock, .ticker-track, .live-dot, .ring { animation: none; }
  .bub, .mock-call, .mock-note, .mock-dispo { animation: none; opacity: 1; }
}
