/* /pricing — the one page that answers every money question, and the page
 * a buyer reads before pressing Buy.
 *
 * Redrawn 9 Oct 2026 when the offer was productized, and cut to one plan on
 * 10 Oct 2026 (Starter and Dealer edition merged). The top half is what
 * onlyWA charges and what it buys: the plan beside DealerSaarthi with the
 * period toggle, what the one fixed-scope setup includes, the two add-ons,
 * what a client must have ready, what we cannot promise, and how billing
 * works. Every rupee in
 * that half is read from window.onlywaCatalog (src/data/catalog.js), never
 * typed here.
 *
 * The bottom half is what Meta charges per message. It exists because
 * prospects and clients kept asking, and because 1 October 2026 made the old
 * shorthand — "replies are free" — untrue. The rate card shows by default;
 * the long part (what changed on 1 October, every feature's cost, a worked
 * month) sits behind one disclosure so the screen stays calm for a buyer and
 * complete for a client. Every number in that half is read out of META_RATES
 * below and the worked examples are arithmetic on those rates. Meta may
 * change prices only on 1 January, 1 April, 1 July and 1 October: re-read
 * Meta's pages before each of those dates, correct the rates and move
 * `verified` — the page prints that date, so a stale check is visible to
 * the reader rather than hidden from them.
 *
 * Page-scoped CSS sits in the <style> block at the bottom, every class
 * prefixed .mp-; styles.css carries only the plan cards and form primitives
 * it shares with the home page and /checkout.
 */

/* Meta's published India rate card, in rupees per delivered message, before
 * GST. `service: null` in `current` is not zero-by-omission: free-form replies
 * are genuinely not charged until 1 October 2026, and null says "no rate
 * exists yet" where 0 would say "Meta charges nothing forever".
 * `authInternational` is carried for completeness of the rate card even though
 * no row shows it — onlyWA sends no one-time passwords, so it never applies. */
const META_RATES = {
  verified: '17 September 2026',   // the day these were read off Meta's pages; update when re-checked
  gst: 18,
  current: { effective: '1 July 2026', marketing: 0.8631, utility: 0.1150, authentication: 0.1150, authInternational: 2.4971, service: null },
  next:    { effective: '1 October 2026', marketing: 0.8631, utility: 0.1150, authentication: 0.1150, authInternational: 2.4971, service: 0.1150, freeServicePerNumberPerMonth: 1000 },
  deadlines: { paymentMethod: '30 September 2026', inrMigration: '31 December 2026' },
  // Volume discounts exist only for utility and authentication; India's first
  // one starts at this message number in a month. Marketing never gets one.
  utilityVolumeTierFrom: 25000001,
  // Meta's own AI responder, priced per token rather than per message. Here so
  // the side note in the October block has nowhere else to get its numbers.
  businessAgent: { since: '1 August 2026', usdPerMillionTokens: 2, usCentsPerReplyLow: 4, usCentsPerReplyHigh: 5 },
};

/* The worked example in section G. Illustrative counts, kept beside the rates
 * so the totals underneath are arithmetic and cannot drift from the labels
 * above them — change a count here and every rupee on that table follows. */
const MP_EXAMPLE = {
  numbers: 2,
  broadcastList: 6000,
  broadcastDelivered: 4200,
  serviceDue: 1500,
  insurance: 400,
  bookingInWindow: 200,
  repliesAcrossNumbers: 3200,
  digestDays: 31,
  shop: { delivered: 1200, reminders: 40, chats: 700 },
};

/* ---- formatting ----------------------------------------------------------
 * Rates print with four decimals because that is how Meta publishes them;
 * rounding ₹0.8631 to ₹0.86 on a page whose job is exactness would be a lie
 * of tidiness. Money and counts use the Indian grouping (en-IN), and rupee
 * totals round to paise once, at the end. */
const mpRound2 = n => Math.round((n + Number.EPSILON) * 100) / 100;
const mpRate = n => '₹' + n.toFixed(4);
const mpMoney = n => '₹' + mpRound2(n).toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
const mpRupees = n => '₹' + Math.round(n).toLocaleString('en-IN');
const mpCount = n => Math.round(n).toLocaleString('en-IN');
const mpPaise = n => String(mpRound2(n * 100));          // 0.1150 -> "11.5"
const mpPaiseAbout = n => String(Math.round(n * 100));   // 0.8631 -> "86"
const mpCrore = n => String(mpRound2(n / 10000000 * 10) / 10); // 25000001 -> "2.5"
/* GST is applied to the rounded rupee total, not to the unrounded sum, because
 * that is what an invoice does — Meta bills a rupees-and-paise figure and adds
 * tax to it. Compounding the unrounded remainder would put us a paisa out. */
const mpWithGst = n => mpRound2(mpRound2(n) * (1 + META_RATES.gst / 100));

const { useState: useStateMp, useEffect: useEffectMp } = React;

/* ---- A. Hero ----------------------------------------------------------- */

function MpHero() {
  const jumps = [
    { href: '#pricing', label: 'The plan' },
    { href: '#setup', label: 'What setup includes' },
    { href: '#addons', label: 'Add-ons' },
    { href: '#ready', label: 'What to keep ready' },
    { href: '#billing', label: 'How billing works' },
    { href: '#meta', label: 'What WhatsApp charges' },
    { href: '#faq', label: 'Questions' },
  ];
  return (
    <section className="pp-hero pp-tone-paper mp-hero">
      <div className="wrap">
        <div className="mp-hero-inner">
          <div className="pp-eyebrow"><span className="pp-eyebrow-dot" /> Pricing</div>
          <h1 className="pp-title">One plan. One setup. <span className="serif">Nothing per message.</span></h1>
          <p className="pp-sub">
            One fixed plan with every feature in it — the dealership ones switch on when you
            are a dealership. A fixed-scope setup done with you, and Meta's own per-message
            charges billed to you directly — we add nothing on top. Buy online in a few
            minutes, or book a call first.
          </p>
          <nav className="mp-jump" aria-label="On this page">
            {jumps.map(j => <a key={j.href} href={j.href} className="mp-jumplink">{j.label}</a>)}
          </nav>
        </div>
      </div>
    </section>
  );
}

/* ---- B. Plans ------------------------------------------------------------
 * <Pricing /> (pricing.jsx) owns the cards. The period lives in the URL
 * (?cycle=3) so a link to "the yearly price" opens on the yearly price. */

function MpPlans() {
  const fromUrl = Number(new URLSearchParams(location.search).get('cycle'));
  const [cycle, setCycle] = useStateMp([1, 3, 12].includes(fromUrl) ? fromUrl : 1);
  useEffectMp(() => {
    const u = new URL(location.href);
    if (cycle === 1) u.searchParams.delete('cycle'); else u.searchParams.set('cycle', String(cycle));
    history.replaceState(null, '', u);
  }, [cycle]);
  return (
    <div className="mp-fee">
      <Pricing standalone cycle={cycle} onCycle={setCycle} />
    </div>
  );
}

/* ---- C. What setup includes ----------------------------------------------
 * Fixed scope, required with every new plan, so a buyer can see exactly what
 * the one-time fee buys before pressing Buy. ONE setup since 10 Oct 2026, at
 * one price for everyone: the list every business gets, and beside it what
 * the same setup also covers for a car dealership (it was the ₹29,999
 * "Dealer setup" until the plans merged). Nothing here promises a Meta
 * outcome: "filed", "submitted", "set up with you". */

const SETUP_ALL = [
  'Meta Business account set up in your business’s name — or your existing one tidied up — with onlyWA added as partner',
  'Business verification filed with Meta, and filed again free if Meta rejects it',
  'Your number moved onto the official WhatsApp Business Platform, display name submitted',
  'Meta’s payment method set up with you, so Meta bills you directly',
  '5 message templates written in English or Hindi and submitted',
  'Your customer list cleaned and imported, consent recorded',
  'Team logins and a 1-hour training session',
  'Your first broadcast sent together',
];
const SETUP_DEALERSHIP = [
  'Your DMS export imported — service, insurance, PUC and warranty dates',
  'Sales and Workshop on separate numbers, with per-number roles',
  'Service, insurance, PUC and warranty reminders switched on',
  'Your first festival campaign planned and sent with you',
];

function MpSetup() {
  const { data, rupees } = window.onlywaCatalog;
  return (
    <section id="setup" className="pp-block">
      <div className="wrap">
        <div className="sec-head">
          <h2>What the one-time setup <span className="serif">includes</span>.</h2>
          <p>Fixed scope, done with you, required once with every new plan. The things a business cannot easily do alone the first time.</p>
        </div>
        <div className="mp-setup-card">
          <div className="mp-setup-head">
            <div>
              <h3>Setup</h3>
              <div className="mp-setup-for">Once, with every new onlyWA plan</div>
            </div>
            <div className="mp-setup-price">{rupees(data.plans.starter.setup_inr)}<small>one-time + GST</small></div>
          </div>
          <div className="mp-setup-cols">
            <ul className="mp-ticks">
              {SETUP_ALL.map(i => <li key={i}>{i}</li>)}
            </ul>
            <div className="mp-setup-dealer">
              <p className="mp-setup-plus">For a car dealership, setup also covers</p>
              <ul className="mp-ticks">
                {SETUP_DEALERSHIP.map(i => <li key={i}>{i}</li>)}
              </ul>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ---- D. Add-ons ----------------------------------------------------------
 * Tick only if needed. The Facebook copy says "we sit with you while you
 * create it": under Meta's terms the owner's personal Facebook profile must
 * be their own, so onlyWA never creates a personal account for anyone — the
 * Page and the Instagram business account are the deliverable. */

function MpAddons() {
  const { data, rupees } = window.onlywaCatalog;
  const items = [
    {
      code: 'social',
      title: data.addons.social.label,
      price: data.addons.social.price_inr,
      body: 'A Facebook Page and an Instagram business account created in your business’s name and linked to your Meta Business account, ready for ads. We sit with you while you create the personal Facebook profile Meta requires behind them — that one must be your own.',
    },
    {
      code: 'website',
      title: data.addons.website.label,
      price: data.addons.website.price_inr,
      body: 'A domain registered in your name, a one-page website on it with HTTPS and a WhatsApp button, hosted for a year. Meta’s business verification often asks for a website on the business’s own domain, and a declined display name is a week lost.',
    },
  ];
  return (
    <section id="addons" className="pp-block pp-tone-paper-2">
      <div className="wrap">
        <div className="sec-head">
          <h2>Add-ons, <span className="serif">only if you need them</span>.</h2>
          <p>Ticked at checkout, one-time, done during setup. Most businesses that already have a page and a website need neither.</p>
        </div>
        <div className="mp-addons">
          {items.map(a => (
            <div key={a.code} className="mp-addon">
              <div className="mp-addon-head">
                <h3>{a.title}</h3>
                <div className="mp-addon-price">{rupees(a.price)}<small>one-time + GST</small></div>
              </div>
              <p>{a.body}</p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

/* ---- E. What you need ready ----------------------------------------------
 * From docs/CLIENT-ONBOARDING.md §1 — the things that, chased one at a time,
 * turn a week into three. Said before the purchase so nobody is surprised
 * after it. */

function MpReady() {
  const items = [
    { t: 'A phone number for the platform', d: 'A fresh SIM is cleanest. A number on the official platform cannot also run the WhatsApp Business app on a handset, and an app number’s chat history does not come across.' },
    { t: 'Business documents', d: 'Your GST certificate, or a utility bill plus a registration certificate. They must match the legal name of the business exactly; two legal entities need two sets.' },
    { t: 'Your Meta Business account login, if you have one', d: 'We use the one you have rather than make a second. If you have none, setup creates it with you.' },
    { t: 'A debit or credit card for Meta’s bill', d: 'Meta delivers nothing without a payment method on your WhatsApp Business Account. We set it up with you during setup; Meta bills it directly.' },
    { t: 'A website on your own domain', d: 'Not strictly required, but Meta’s verification and display-name review go better with one. The website add-on covers it if you have none.' },
    { t: 'Your customer list as one file', d: 'The export from your DMS or billing software — a spreadsheet, not a screenshot. We clean and import it with you.' },
  ];
  return (
    <section id="ready" className="pp-block">
      <div className="wrap">
        <div className="sec-head">
          <h2>What to keep ready <span className="serif">before setup starts</span>.</h2>
          <p>Send it all in one go and the setup is an afternoon of our work; the rest of the clock is Meta’s.</p>
        </div>
        <ol className="mp-ready">
          {items.map((it, i) => (
            <li key={it.t}>
              <span className="mp-ready-n" aria-hidden="true">{i + 1}</span>
              <div><h4>{it.t}</h4><p>{it.d}</p></div>
            </li>
          ))}
        </ol>
      </div>
    </section>
  );
}

/* ---- F. What we cannot promise --------------------------------------------
 * Short, and above the fold of the billing section on purpose. Meta decides
 * verification, display names, templates and delivery (Terms §4); the only
 * honest promise is that we file it right and file again free. */

function MpHonest() {
  return (
    <section id="honest" className="pp-block pp-tone-paper-2">
      <div className="wrap">
        <div className="mp-honest">
          <div className="mp-honest-head">
            <div className="eyebrow">What we can’t promise</div>
            <h2>Meta decides. <span className="serif">We file it right.</span></h2>
          </div>
          <div className="mp-honest-body">
            <p>Business verification, your display name and every message template are approved by Meta, not by onlyWA. We cannot sell you &ldquo;WhatsApp API approved&rdquo; — nobody can. What we do: file each of them properly the first time, and file again at no charge if Meta rejects one.</p>
            <p>Meta’s reviews usually take from a day to a couple of weeks, and nobody can speed them up. Meta also decides what gets delivered, how many marketing messages one person may receive, and your daily sending limit — so no delivery rate is promised. The full list is <a href="/terms#what-meta-controls">section 4 of our terms</a>.</p>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ---- G. How billing works -------------------------------------------------
 * Restates refund.html, shipping.html and Terms §5 and §8 in plain words;
 * it must never say something those pages do not. Renewals are paid by link
 * from inside the app — there is no auto-debit, nothing is charged without
 * the client pressing Pay. */

function MpBilling() {
  const facts = [
    { t: 'What you pay today', d: 'The plan for the period you chose, the setup, and any add-on you ticked — plus 18% GST. Paid online through Razorpay: UPI, cards or netbanking. A GST invoice for every payment.' },
    { t: 'Your login', d: 'Usually the moment you have paid: your order page and your email let you set a password straight away. Always within 2 working days. Setup work starts in the same window.' },
    { t: 'Renewals', d: 'Each period you pay the plan again from inside the app, by payment link. No auto-debit — nothing is charged without you pressing Pay.' },
    { t: 'Stopping', d: 'Your plan renews for another period of the same length unless either side gives 30 days’ written notice before it ends. A period already paid for is not refunded — see the refund policy for the three exceptions.' },
    { t: 'Meta’s bill', d: 'Meta charges your own WhatsApp Business Account per delivered message, at its published rates, on its own invoice. onlyWA never collects it and adds nothing to it.' },
    { t: 'The AI assistant', d: 'Runs on your own API key only if you switch it on; that provider bills you for what the model uses. Leave it off and this bill does not exist.' },
  ];
  return (
    <section id="billing" className="pp-block">
      <div className="wrap">
        <div className="sec-head">
          <h2>How billing <span className="serif">works</span>.</h2>
          <p>Three bills at most — ours, Meta’s, and your AI provider’s if you use one — each in your own name.</p>
        </div>
        <div className="mp-facts">
          {facts.map(f => (
            <div key={f.t} className="mp-fact">
              <h4>{f.t}</h4>
              <p>{f.d}</p>
            </div>
          ))}
        </div>
        <p className="mp-foot">
          The words that bind are in the <a href="/terms">Terms of Service</a>, the <a href="/refund">Cancellation &amp; Refund Policy</a> and the <a href="/shipping">Delivery Policy</a>. Your order, with those, is your Order Form.
        </p>
      </div>
    </section>
  );
}

/* ---- D. What Meta charges per message in India -------------------------- */

function MpMetaRates() {
  const now = META_RATES.current;
  const next = META_RATES.next;
  const rows = [
    {
      kind: 'Marketing template',
      what: 'festival offers, new arrivals, stock clearance, greetings',
      now: mpRate(now.marketing),
      next: mpRate(next.marketing),
    },
    {
      kind: 'Utility template',
      what: 'service due, insurance expiry, booking confirmation, progress update',
      now: mpRate(now.utility),
      next: mpRate(next.utility),
    },
    {
      kind: 'Authentication template',
      what: 'one-time passwords (onlyWA sends none)',
      now: mpRate(now.authentication),
      next: mpRate(next.authentication),
    },
    {
      kind: 'Service message (free-form reply inside the 24-hour window)',
      what: 'journeys, AI assistant, team replies, photos, PDFs',
      now: 'Free',
      next: `First ${mpCount(next.freeServicePerNumberPerMonth)} a month per number free, then ${mpRate(next.service)}`,
    },
    { kind: "Customer's message to you", what: '—', now: 'Free', next: 'Free' },
    {
      kind: 'Any message inside a 72-hour free entry point window',
      what: 'from a Click-to-WhatsApp ad',
      now: 'Free',
      next: 'Free',
    },
  ];

  const notes = [
    'A template is a message Meta approved in advance. It is the only kind of message you can send to someone who has not written to you in the last 24 hours. Meta decides its category — a "reminder" submitted as utility can be classed marketing if it reads like an offer, and the app shows you when that happens.',
    `Volume discounts exist only for utility and authentication and start at ${mpCrore(META_RATES.utilityVolumeTierFrom)} crore utility messages a month. For a dealership the list rate is the rate. Marketing has no volume discount for anyone — Zomato pays the same ${mpPaiseAbout(now.marketing)} paise you do.`,
    'The rate follows the customer’s country code, not yours. This table is for +91 numbers; a message to a customer on a +44 or +971 number is charged at that country’s rate instead.',
    `Meta's card carries one more line, authentication-international (${mpRate(next.authInternational)}): a higher rate for one-time passwords in the cases Meta defines. onlyWA sends no one-time passwords, so it never appears on your bill.`,
    'Meta changes prices only on 1 January, 1 April, 1 July and 1 October, with at least a month’s notice. We re-check these pages before each of those dates and change the "checked on" date above.',
  ];

  const rough = [
    { label: `${mpCount(1000)} marketing messages`, value: mpRupees(1000 * next.marketing) },
    { label: `${mpCount(1000)} utility`, value: mpRupees(1000 * next.utility) },
    { label: `${mpCount(1000)} service messages beyond the free tier`, value: mpRupees(1000 * next.service) },
  ];

  return (
    <section id="meta" className="pp-block">
      <div className="wrap">
        <div className="sec-head">
          <h2>What Meta charges per message, <span className="serif">in India</span>.</h2>
          <p>Read off Meta's own rate card on {META_RATES.verified}. Charged only when a message is delivered. Rates are before GST.</p>
        </div>

        <div className="mp-tablewrap mp-rtable-wrap">
          <table className="mp-table mp-table-rates">
            <thead>
              <tr>
                <th scope="col">Message</th>
                <th scope="col">What it is</th>
                <th scope="col">Until 30 Sep 2026</th>
                <th scope="col">From 1 Oct 2026</th>
              </tr>
            </thead>
            <tbody>
              {rows.map(r => (
                <tr key={r.kind}>
                  <th scope="row">{r.kind}</th>
                  <td className="mp-dim">{r.what}</td>
                  <td className="mp-num">{r.now}</td>
                  <td className="mp-num">{r.next}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
        <p className="mp-scrollhint w700" aria-hidden="true">Scroll the table sideways to compare →</p>

        {/* Same rows as labelled cards for handsets: on a 375px screen the two
            rate columns of the table sit off to the right, and a rate page
            whose rates need a sideways scroll to find has failed at its job. */}
        <div className="mp-rcards">
          {rows.map(r => (
            <div key={r.kind} className="mp-fcard">
              <div className="mp-fcard-head"><span className="mp-fcard-name">{r.kind}</span></div>
              <dl className="mp-fcard-lines">
                <dt>What it is</dt><dd>{r.what}</dd>
                <dt>Until 30 Sep 2026</dt><dd className="mp-num">{r.now}</dd>
                <dt>From 1 Oct 2026</dt><dd className="mp-num">{r.next}</dd>
              </dl>
            </div>
          ))}
        </div>

        <ul className="mp-notes">
          {notes.map((n, i) => <li key={i}>{n}</li>)}
        </ul>

        <div className="mp-rough">
          <table className="mp-minitable">
            <caption>Rupees, roughly</caption>
            <tbody>
              {rough.map(r => (
                <tr key={r.label}>
                  <th scope="row">{r.label}</th>
                  <td className="mp-num">≈ {r.value}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </section>
  );
}
/* ---- E. What changes on 1 October 2026 ----------------------------------
 * Ink-toned on purpose. It is the one part of this page a reader who already
 * knows our pricing still needs, so it must not read as more of the same. */

function MpOctober() {
  const next = META_RATES.next;
  const journeySteps = 5;   // the word "five-step" below is prose; this is what makes the paise
  const ba = META_RATES.businessAgent;
  const items = [
    {
      title: 'Replies inside the 24-hour window are no longer free.',
      body: `Every free-form message — a journey step, an AI reply, a team reply, a photo — is charged at ${mpRate(next.service)} once delivered.`,
      means: `a five-step journey costs ${mpPaise(journeySteps * next.service)} paise per customer beyond the free tier; a marketing broadcast to that same customer costs ${mpPaiseAbout(next.marketing)} paise.`,
    },
    {
      title: `The first ${mpCount(next.freeServicePerNumberPerMonth)} service messages a month on each of your numbers are free.`,
      body: `Meta's words: "a free monthly tier of ${mpCount(next.freeServicePerNumberPerMonth)} service messages per business phone number." A dealership on a Sales number and a Workshop number gets ${mpCount(2 * next.freeServicePerNumberPerMonth)}. Meta has published nothing more about the tier yet — how the month is counted, whether unused messages carry over — and we will confirm it against the first October invoice and update this line.`,
    },
    {
      title: 'A utility template sent inside the window is charged too.',
      body: `Until now a booking confirmation or a reminder that went out while the customer's 24-hour window was open was free; from 1 October it is ${mpRate(next.utility)} like any other utility message.`,
    },
    {
      title: `Have a payment method on file by ${META_RATES.deadlines.paymentMethod}.`,
      body: 'Meta stops delivering service messages on accounts without one. If your account already sends broadcasts it already has one — Meta would not have delivered a template without it — so the only job is to keep the card valid.',
    },
    {
      title: 'What does not change:',
      body: `marketing ${mpRate(next.marketing)}, utility ${mpRate(next.utility)}, authentication ${mpRate(next.authentication)}, customer messages free, the 72-hour free window after a Click-to-WhatsApp ad, and the rule that you pay only for delivered messages.`,
    },
  ];

  return (
    <section id="october" className="pp-block">
      <div className="wrap">
        <div className="mp-oct">
          <div className="mp-oct-eyebrow">Effective {next.effective} · announced by Meta 1 July 2026, rates published 1 September 2026</div>
          <h2 className="mp-oct-title">What changes on <span className="serif">{next.effective}</span>.</h2>
          <ol className="mp-oct-list">
            {items.map((it, i) => (
              <li key={i} className="mp-oct-item">
                <span className="mp-oct-num" aria-hidden="true">{i + 1}</span>
                <div>
                  <p className="mp-oct-body">
                    <strong>{it.title}</strong> {it.body}
                  </p>
                  {it.means && <p className="mp-oct-means"><em>What it means:</em> {it.means}</p>}
                </div>
              </li>
            ))}
          </ol>
          <p className="mp-oct-side">
            Meta's own AI responder, Meta Business Agent, has been charged per token since {ba.since}
            {' '}(US ${ba.usdPerMillionTokens} per million tokens, roughly {ba.usCentsPerReplyLow}–{ba.usCentsPerReplyHigh} US cents a reply).
            onlyWA does not use it. If you switch it on in WhatsApp Manager it takes over replies on
            that number, so leave it off unless you have decided to move to it.
          </p>
        </div>
      </div>
    </section>
  );
}
/* ---- F. Feature by feature ----------------------------------------------
 * The centrepiece: an owner should be able to point at a line in the app and
 * find it here. It is exhaustive because every WhatsApp message the app sends
 * goes through one sender — so "not on this list" means "sends nothing".
 * Rendered twice: a real <table> on desktop (scope-d headers, one scan across
 * the two rate columns) and labelled cards under 720px, because a six-column
 * table on a 375px handset is a table nobody reads. */

const MP_PILL_LABEL = { nochange: 'No change', new: 'New charge', free: 'Free', zero: '₹0' };

/* Built once at module load, not inside MpFeatures' render: every row is
 * arithmetic on META_RATES, which never changes after the page mounts. */
const MP_FEATURE_GROUPS = (function mpFeatureGroups() {
  const now = META_RATES.current;
  const next = META_RATES.next;
  const free = mpCount(next.freeServicePerNumberPerMonth);
  return [
    {
      title: 'Reaching out (templates, sent outside the 24-hour window)',
      rows: [
        { feature: 'Broadcasts — festival offer, new arrival, stock clearance', sends: 'one marketing template per person', category: 'Marketing', now: `${mpRate(now.marketing)} per delivered`, next: mpRate(next.marketing), status: 'nochange' },
        { feature: 'Broadcasts sent with a utility template (information, not an offer)', sends: 'one utility template per person', category: 'Utility', now: mpRate(now.utility), next: mpRate(next.utility), status: 'nochange' },
        { feature: 'Service, insurance, PUC and warranty reminders', sends: 'one utility template per vehicle due', category: 'Utility', now: mpRate(now.utility), next: mpRate(next.utility), status: 'nochange' },
        { feature: 'Birthday and anniversary greetings', sends: 'Meta classes greetings as marketing', category: 'Marketing', now: mpRate(now.marketing), next: mpRate(next.marketing), status: 'nochange' },
        { feature: 'Automations — lead follow-up, test-drive follow-up, no-show, delivery referral, post-service feedback, dormant win-back, insurance lapsed…', sends: "one template per step, category is the template's", category: 'Utility or Marketing', now: `${mpRate(now.utility)} or ${mpRate(now.marketing)}`, next: 'same', nextNote: `except a step that lands while the person's window is open and uses a utility template: free → ${mpRate(next.utility)}`, status: 'nochange' },
        { feature: "Owner's daily WhatsApp digest", sends: "one utility template a day to the owner's phone", category: 'Utility', now: `${mpRate(now.utility)} a day`, next: `${mpRate(next.utility)} a day`, status: 'nochange' },
        { feature: '"Send a test to me"', sends: 'one real template to your own phone', category: "the template's", now: 'charged like the template', next: 'same', status: 'nochange' },
        { feature: '"Test without sending" (dry run)', sends: 'nothing', category: '—', now: '₹0', next: '₹0', status: 'free' },
        { feature: 'Builders: booking confirmation card', sends: 'one utility template with the card as its image', category: 'Utility', now: `${mpRate(now.utility)} (free if the buyer wrote in the last 24h)`, next: mpRate(next.utility), status: 'new', statusNote: 'inside the window' },
        { feature: 'Builders: project progress update', sends: 'one utility template per booker', category: 'Utility', now: mpRate(now.utility), next: mpRate(next.utility), status: 'nochange' },
        { feature: 'Builders: channel-partner weekly leaderboard', sends: 'one marketing template per partner', category: 'Marketing', now: mpRate(now.marketing), next: mpRate(next.marketing), status: 'nochange' },
      ],
    },
    {
      title: 'Replying (service messages, inside the 24-hour window)',
      rows: [
        { feature: 'Journeys — front door, workshop door, test drive, True Value, brochure-first…', sends: 'one free-form message per step (text, buttons, list, photo)', category: 'Service', now: 'Free', next: `first ${free} a month per number free, then ${mpRate(next.service)} per step`, status: 'new' },
        { feature: 'AI assistant replies', sends: "free-form text (and the builders' availability chart image)", category: 'Service', now: "Free, plus your AI provider's bill", next: `first ${free} free, then ${mpRate(next.service)}, plus your AI provider's bill (unchanged)`, status: 'new' },
        { feature: 'Team replies from the shared inbox — text, photo, PDF', sends: 'free-form', category: 'Service', now: 'Free', next: `first ${free} free, then ${mpRate(next.service)}`, status: 'new' },
        { feature: 'A template sent from the inbox while the window is open', sends: 'a utility or marketing template', category: 'Utility / Marketing', now: `utility free, marketing ${mpRate(now.marketing)}`, next: `utility ${mpRate(next.utility)}, marketing ${mpRate(next.marketing)}`, status: 'new', statusNote: 'utility' },
        { feature: "Builders: automatic reply to a channel partner's shared contact card", sends: 'one free-form message per card', category: 'Service', now: 'Free', next: `counts against the ${free}, then ${mpRate(next.service)}`, status: 'new' },
        { feature: 'Automatic recovery when Meta refuses a marketing message for the per-person cap', sends: 'the same words re-sent as a plain reply, only if the person wrote in the last 24h', category: 'Service', now: 'Free', next: `counts against the ${free}, then ${mpRate(next.service)} — still cheaper than the ${mpPaiseAbout(next.marketing)} paise it replaces`, status: 'new' },
        { feature: 'Replies to a Click-to-WhatsApp ad lead within 24 hours', sends: 'free-form or template, inside the 72-hour free window', category: '—', now: 'Free for delivery', next: 'Free for delivery', status: 'nochange' },
      ],
    },
    {
      title: 'Never charged',
      rows: [
        { feature: 'A message Meta refuses — per-person marketing cap, invalid number, closed window', sends: 'not delivered', category: '—', now: '₹0', next: '₹0', status: 'free' },
        { feature: 'STOP / opt-out handling', sends: 'nothing is sent back', category: '—', now: '₹0', next: '₹0', status: 'free' },
        { feature: "Customers' messages to you", sends: 'inbound', category: '—', now: '₹0', next: '₹0', status: 'free' },
      ],
    },
    {
      title: 'No WhatsApp message involved',
      rows: [
        { feature: 'Templates screen (submitting, editing, syncing), number setup, CSV import, customer list, segments, reports, ad results, media library, site visits, units', sends: 'Meta API calls, no messages', category: '—', now: '₹0', next: '₹0', status: 'zero' },
        { feature: 'Social posts scheduled to Facebook and Instagram', sends: 'a post, not a message', category: '—', now: '₹0 from WhatsApp (ad spend is separate)', next: 'same', status: 'zero' },
        { feature: 'Email alerts — new lead, unanswered-chat escalation, invites, support', sends: 'email', category: '—', now: '₹0', next: '₹0', status: 'zero' },
      ],
    },
  ];
})();

function MpPill({ status, note }) {
  const tone = status === 'nochange' ? 'same' : status === 'new' ? 'new' : 'mint';
  return (
    <span className="mp-pillwrap">
      <span className={`mp-pill ${tone}`}>{MP_PILL_LABEL[status]}</span>
      {note && <span className="mp-pill-note">{note}</span>}
    </span>
  );
}

function MpFeatures() {
  const groups = MP_FEATURE_GROUPS;
  return (
    <section id="features" className="pp-block pp-tone-paper-2">
      <div className="wrap">
        <div className="sec-head">
          <h2>What each feature costs to run, <span className="serif">feature by feature</span>.</h2>
          <p>Every WhatsApp message the app sends goes out through one door, so this list is complete. Counts are what Meta delivers, not what you press send on — a refused or undelivered message is never charged.</p>
        </div>

        <div className="mp-tablewrap mp-ftable-wrap">
          <table className="mp-table mp-table-features">
            <thead>
              <tr>
                <th scope="col">Feature</th>
                <th scope="col">What goes out</th>
                <th scope="col">Meta's category</th>
                <th scope="col">Until 30 Sep 2026</th>
                <th scope="col">From 1 Oct 2026</th>
                <th scope="col">Status</th>
              </tr>
            </thead>
            {groups.map(g => (
              <tbody key={g.title}>
                <tr className="mp-group">
                  <th scope="colgroup" colSpan={6}>{g.title}</th>
                </tr>
                {g.rows.map(r => (
                  <tr key={r.feature}>
                    <th scope="row">{r.feature}</th>
                    <td className="mp-dim">{r.sends}</td>
                    <td className="mp-dim">{r.category}</td>
                    <td className="mp-num">{r.now}</td>
                    <td className="mp-num">
                      {r.next}
                      {r.nextNote && <span className="mp-cellnote">{r.nextNote}</span>}
                    </td>
                    <td><MpPill status={r.status} note={r.statusNote} /></td>
                  </tr>
                ))}
              </tbody>
            ))}
          </table>
        </div>

        {/* Same rows, stacked and labelled, for handsets. */}
        <div className="mp-fcards">
          {groups.map(g => (
            <div key={g.title} className="mp-fgroup">
              <h3 className="mp-fgroup-title">{g.title}</h3>
              {g.rows.map(r => (
                <div key={r.feature} className="mp-fcard">
                  <div className="mp-fcard-head">
                    <span className="mp-fcard-name">{r.feature}</span>
                    <MpPill status={r.status} note={r.statusNote} />
                  </div>
                  <dl className="mp-fcard-lines">
                    <dt>What goes out</dt><dd>{r.sends}</dd>
                    <dt>Meta's category</dt><dd>{r.category}</dd>
                    <dt>Until 30 Sep 2026</dt><dd className="mp-num">{r.now}</dd>
                    <dt>From 1 Oct 2026</dt>
                    <dd className="mp-num">{r.next}{r.nextNote && <span className="mp-cellnote">{r.nextNote}</span>}</dd>
                  </dl>
                </div>
              ))}
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}
/* ---- G. A month, worked out ---------------------------------------------
 * Nothing in this table is typed: every rupee is count × rate out of
 * META_RATES, and the "before 1 October" figure is the same sum with the two
 * new lines removed. Change a rate above and this section re-argues itself. */

function MpExample() {
  const ex = MP_EXAMPLE;
  const next = META_RATES.next;
  const freeReplies = ex.numbers * next.freeServicePerNumberPerMonth;
  const chargeableReplies = ex.repliesAcrossNumbers - freeReplies;

  const lines = [
    { label: `Diwali offer broadcast — ${mpCount(ex.broadcastList)} on the list, Meta delivers ${mpCount(ex.broadcastDelivered)} (a cold list always has refusals)`, count: ex.broadcastDelivered, rate: next.marketing },
    { label: 'Service-due reminders (utility)', count: ex.serviceDue, rate: next.utility },
    { label: 'Insurance-expiry reminders (utility)', count: ex.insurance, rate: next.utility },
    { label: "Utility templates sent from the inbox while the customer's window was open — service-booking and pick-up confirmations", count: ex.bookingInWindow, rate: next.utility, isNew: true },
    { label: `Replies by journeys, the AI assistant and the team — ${mpCount(ex.repliesAcrossNumbers)} across two numbers; the first ${mpCount(freeReplies)} are free`, count: chargeableReplies, rate: next.service, isNew: true },
    { label: "Owner's daily digest", count: ex.digestDays, rate: next.utility },
  ];

  const total = lines.reduce((s, l) => s + l.count * l.rate, 0);
  const added = lines.filter(l => l.isNew).reduce((s, l) => s + l.count * l.rate, 0);
  const before = total - added;
  const addedPct = Math.round(added / before * 100);

  const shopBroadcast = ex.shop.delivered * next.marketing;
  const shopReminders = ex.shop.reminders * next.utility;

  return (
    <section id="example" className="pp-block">
      <div className="wrap">
        <div className="sec-head">
          <h2>A festive month at a dealership, <span className="serif">worked out</span>.</h2>
          <p>Illustrative counts for a Maruti dealership on two numbers (Sales and Workshop) in October 2026. Your own delivered counts are in the app after every send; multiply by the rates above.</p>
        </div>

        <div className="mp-tablewrap mp-etable-wrap">
          <table className="mp-table mp-table-example">
            <thead>
              <tr>
                <th scope="col">What went out</th>
                <th scope="col">Delivered</th>
                <th scope="col">Rate</th>
                <th scope="col">₹</th>
              </tr>
            </thead>
            <tbody>
              {lines.map(l => (
                <tr key={l.label}>
                  <th scope="row">
                    {l.label}
                    {l.isNew && <span className="mp-newtag">new from 1 Oct</span>}
                  </th>
                  <td className="mp-num">{mpCount(l.count)}</td>
                  <td className="mp-num">{mpRate(l.rate)}</td>
                  <td className="mp-num mp-strong">{mpMoney(l.count * l.rate)}</td>
                </tr>
              ))}
            </tbody>
            <tfoot>
              <tr className="mp-total">
                <th scope="row" colSpan={3}>Meta's charge before GST</th>
                <td className="mp-num mp-strong">{mpMoney(total)}</td>
              </tr>
              <tr>
                <th scope="row" colSpan={3}>With {META_RATES.gst}% GST</th>
                <td className="mp-num">{mpMoney(mpWithGst(total))}</td>
              </tr>
            </tfoot>
          </table>
        </div>
        {/* The same sum as cards for handsets, one line of arithmetic each, so
            the rupee figure sits under its label instead of three columns to
            the right of it. The totals are the same variables as the tfoot. */}
        <div className="mp-ecards">
          {lines.map(l => (
            <div key={l.label} className="mp-fcard">
              <div className="mp-fcard-head">
                <span className="mp-fcard-name">
                  {l.label}
                  {l.isNew && <span className="mp-newtag">new from 1 Oct</span>}
                </span>
              </div>
              <p className="mp-ecard-sum">
                {mpCount(l.count)} × {mpRate(l.rate)} = <strong>{mpMoney(l.count * l.rate)}</strong>
              </p>
            </div>
          ))}
          <div className="mp-fcard mp-ecard-total">
            <dl className="mp-fcard-lines">
              <dt>Before GST</dt><dd className="mp-num mp-strong">{mpMoney(total)}</dd>
              <dt>With {META_RATES.gst}% GST</dt><dd className="mp-num">{mpMoney(mpWithGst(total))}</dd>
            </dl>
          </div>
        </div>

        <p className="mp-said">
          The same month before 1 October would have been {mpMoney(before)}. The change adds {mpRupees(added)} —
          about {addedPct}% — because a dealership's money goes on the broadcast, not the replies.
        </p>
        <p className="mp-said">
          A shop on one number that sends one broadcast ({mpCount(ex.shop.delivered)} delivered, {mpMoney(shopBroadcast)}),
          {' '}{mpCount(ex.shop.reminders)} renewal reminders ({mpMoney(shopReminders)}) and answers {mpCount(ex.shop.chats)} chats
          stays under the {mpCount(next.freeServicePerNumberPerMonth)} free replies: Meta's charge
          is {mpMoney(shopBroadcast + shopReminders)} before GST, and 1 October changes nothing.
        </p>
        <p className="mp-said mp-said-last">onlyWA's fee is the flat amount above, whatever these counts are.</p>
      </div>
    </section>
  );
}
/* ---- H. Questions about money -------------------------------------------
 * Same accordion as the homepage FAQ, copied rather than imported (no module
 * system here), with the keyboard handling the homepage one never got: these
 * rows are the answers a client will be hunting for at speed. */

/* Hoisted out of MpFaq: the accordion's own open/close state re-renders the
 * component on every click, and none of these questions depend on that state
 * — only on META_RATES, which is fixed once the page has loaded. */
const MP_FAQ_ITEMS = (function () {
  const next = META_RATES.next;
  return [
    { q: 'Do I pay onlyWA anything per message?', a: 'No. Our fee is the flat plan amount above, invoiced by us. Meta bills your own WhatsApp Business Account for delivered messages at its published rates. We do not collect that money, mark it up or see it.' },
    { q: "Why does the big brand's WhatsApp offer cost the same as mine?", a: 'Because Meta publishes one marketing rate for India and no volume discount on it. What the big brands do differently is send fewer offers and more reminders — utility messages at a seventh of the price — which is exactly what service-due and insurance reminders are here.' },
    { q: 'Do refused or undelivered messages cost anything?', a: 'No. Meta charges only when a message is delivered. A number Meta refuses for the per-person marketing cap, a closed window or an invalid number costs nothing, and the app shows you which ones those were.' },
    { q: 'Why did my bill have messages I never pressed send on?', a: "Reminders, automations and the owner's digest send on their own once you switch them on — that is the point of them. Each one is a template, so each delivered one is on Meta's bill at the utility or marketing rate. The reminders screen shows what goes out tomorrow before it goes." },
    { q: 'A reminder I submitted as utility is being charged as marketing. Why?', a: "Meta's classifier assigns the category when it approves a template, and it reads a reminder with an offer in it as marketing. The app shows you the category Meta assigned. Rewrite the template as pure information — what is due, when, where — and resubmit." },
    { q: `Will journeys and the AI assistant stop after ${mpCount(next.freeServicePerNumberPerMonth)} replies?`, a: `No. They keep running; from the ${mpCount(next.freeServicePerNumberPerMonth + 1)}st reply on that number in the month, Meta charges ${mpPaise(next.service)} paise per delivered reply. A five-step journey is under 60 paise per customer.` },
    { q: 'What happens if my card on the Meta account fails?', a: 'Meta stops delivering — templates today, replies too from 1 October. The app shows the refusal (Meta’s error 131042) on the send. Fix the card in Meta Business Suite → Billing Hub and the next send goes.' },
    { q: 'Is GST on top?', a: "Yes, on both bills. Meta's rates are before GST and Meta adds it on its invoice, as it does for ads. Our fee is quoted before GST too." },
    { q: 'My WhatsApp account bills in dollars. Do I need to do anything?', a: `Yes, before ${META_RATES.deadlines.inrMigration}: Meta requires every account of an India-based business to be on rupees, and from 1 January 2027 it stops delivering from a dollar account. Accounts we set up in 2026 are already in rupees; if yours is older, we move it with you.` },
    { q: 'Does the AI assistant cost extra?', a: "Not from us. It runs on your own API key, so the model's provider bills you for what it uses, and from 1 October each delivered reply also counts as a service message on Meta's bill. Switch it off and both stop." },
    { q: 'Where do I see what Meta charged me?', a: 'In Meta Business Suite under Billing Hub, per account. In the app, every broadcast shows sent, delivered, read and refused counts; delivered × the rate above is the charge.' },
    { q: 'Can Meta change these prices?', a: 'Yes, on the first day of a quarter with at least a month’s notice. This page carries the date we last checked Meta’s pages at the top; that date moves before every quarter.' },
  ];
})();

function MpFaq() {
  const items = MP_FAQ_ITEMS;
  const [open, setOpen] = useStateMp(0);
  const toggle = i => setOpen(open === i ? -1 : i);

  return (
    <section id="faq" className="pp-block pp-tone-paper-2">
      <div className="wrap">
        <div className="sec-head">
          <h2>Questions about <span className="serif">money</span>.</h2>
          <p>The ones that come up once the first invoice lands. Anything else, ask us on WhatsApp.</p>
        </div>
        <div className="faqs mp-faq">
          {items.map((it, i) => (
            <div
              key={i}
              className={`faq ${open === i ? 'open' : ''}`}
              role="button"
              tabIndex={0}
              aria-expanded={open === i}
              onClick={() => toggle(i)}
              onKeyDown={e => {
                if (e.key === 'Enter' || e.key === ' ' || e.key === 'Spacebar') { e.preventDefault(); toggle(i); }
              }}
            >
              <div className="faq-q">
                <span>{it.q}</span>
                <span className="i"><Ic.plus size={14} /></span>
              </div>
              <div className="faq-a">{it.a}</div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}
/* ---- I. Sources ---------------------------------------------------------
 * Printed in full so a client can check us rather than trust us — and so the
 * next person to re-verify knows exactly which four pages to open. */

function MpSources() {
  const sources = [
    { name: 'Pricing on the WhatsApp Business Platform', href: 'https://developers.facebook.com/documentation/business-messaging/whatsapp/pricing' },
    { name: 'Upcoming pricing updates for Meta Business Agent, service and utility messages', href: 'https://developers.facebook.com/documentation/business-messaging/whatsapp/pricing/non-template-messages' },
    { name: 'Rate cards (INR, current and effective 1 October 2026)', note: 'the "Rate cards" section of the pricing page above' },
    { name: 'Pricing explainer (PDF)', note: 'linked from the pricing page' },
    { name: "onlyWA's own terms", href: '/terms.html', note: '§4 — what Meta controls and we do not' },
  ];
  return (
    <section id="sources" className="mp-sources-block">
      <div className="wrap">
        <div className="mp-sources-head">Sources · read {META_RATES.verified}</div>
        <ul className="mp-sources">
          {sources.map(s => (
            <li key={s.name}>
              {s.href
                ? <a href={s.href} target={s.href.startsWith('http') ? '_blank' : undefined} rel={s.href.startsWith('http') ? 'noreferrer' : undefined}>{s.name}</a>
                : <span>{s.name}</span>}
              {s.note && <span className="mp-sources-note"> — {s.note}</span>}
            </li>
          ))}
        </ul>
      </div>
    </section>
  );
}

/* ---- The long part, behind one disclosure ---------------------------------
 * A buyer wants the rate card; a client with an invoice in hand wants every
 * feature's cost and the worked month. Both get what they came for without
 * the other's scroll. The three sections render only once opened, so the
 * page's own reveal observer (pricing.html) never has to know about them. */

function MpDeep() {
  const [open, setOpen] = useStateMp(() => ['#october', '#features', '#example'].includes(location.hash));
  return (
    <div className="mp-deep">
      <div className="wrap">
        <button type="button" className="mp-deep-btn" aria-expanded={open} aria-controls="mp-deep-body" onClick={() => setOpen(o => !o)}>
          <span>
            <b>{open ? 'Hide' : 'Show'} the full breakdown</b>
            <span className="mp-deep-sub">What changed on {META_RATES.next.effective} · what every feature costs to run · a festive month worked out</span>
          </span>
          <span className={`mp-deep-i${open ? ' open' : ''}`} aria-hidden="true"><Ic.plus size={16} /></span>
        </button>
      </div>
      {open && (
        <div id="mp-deep-body">
          <MpOctober />
          <MpFeatures />
          <MpExample />
        </div>
      )}
    </div>
  );
}

/* ---- J. Closing CTA ----------------------------------------------------- */

function MpCTA() {
  return (
    <section className="pp-block">
      <div className="wrap">
        <div className="pp-cta-card">
          <div>
            <div className="pp-eyebrow"><span className="pp-eyebrow-dot" /> Still a question?</div>
            <h2 className="pp-cta-title">Ask it on WhatsApp. <span className="serif">We answer with the number, not a pitch.</span></h2>
          </div>
          <div className="pp-cta-actions">
            <a href="#pricing" className="btn primary">See the plan <Ic.arrow size={14} /></a>
            <BookCallLink className="btn ghost"><Ic.waLogo size={16} /> Book a call</BookCallLink>
            <a href="/demo/dealer" className="btn ghost">See the app</a>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ---- The page ----------------------------------------------------------- */

function PricingPage() {
  return (
    <>
      <MpHero />
      <MpPlans />
      <MpSetup />
      <MpAddons />
      <MpReady />
      <MpHonest />
      <MpBilling />
      <MpMetaRates />
      <MpDeep />
      <MpFaq />
      <MpSources />
      <MpCTA />

      <style>{`
        /* ---- A. Hero ---- */
        .mp-hero { padding-bottom: 36px; }
        .mp-hero-inner { max-width: 860px; }
        .mp-hero-inner .pp-title { max-width: 20ch; }
        .mp-jump { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 28px; }
        .mp-jumplink {
          display: inline-flex; align-items: center; min-height: 40px; padding: 0 14px;
          border: 1px solid var(--line); border-radius: 999px; background: var(--paper);
          color: var(--ink-3); text-decoration: none; font: 500 13.5px/1 var(--f-sans);
          transition: border-color .15s ease, color .15s ease;
        }
        .mp-jumplink:hover { border-color: var(--ink); color: var(--ink); }

        /* ---- B. Plans ----
           Plan cards are --paper-2 in styles.css, so the band behind them
           steps back or the cards vanish into it. */
        .mp-fee { background: var(--paper-2); }
        html.dark .mp-fee { background: var(--paper-2); }
        .mp-fee .plan { background: var(--paper); }
        .mp-fee .plan.feature { background: var(--ink); }
        html.dark .mp-fee .plan { background: var(--paper-3); }

        /* ---- C. Setup ----
           One card, full width: the list every business gets on the left,
           the dealership part in its own accented panel on the right —
           stacked under 860px. */
        .mp-setup-card {
          background: var(--paper-2); border: 1px solid var(--line);
          border-radius: var(--radius-xl); padding: 30px 28px 28px;
        }
        html.dark .mp-setup-card { background: var(--paper-3); }
        .mp-setup-cols { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: 28px; align-items: start; margin-top: 4px; }
        @media (max-width: 860px) { .mp-setup-cols { grid-template-columns: 1fr; gap: 8px; } }
        .mp-setup-dealer {
          margin-top: 20px; padding: 20px 22px 22px; border-radius: var(--radius-lg);
          background: var(--paper); border: 1px solid color-mix(in oklab, var(--accent) 40%, var(--line));
        }
        html.dark .mp-setup-dealer { background: var(--paper-2); }
        .mp-setup-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
        .mp-setup-card h3 { font-size: 22px; letter-spacing: -0.02em; }
        .mp-setup-for { margin-top: 4px; font-size: 13.5px; color: var(--muted); }
        .mp-setup-price { font-family: var(--f-serif); font-style: italic; font-size: 34px; line-height: 1; letter-spacing: -0.02em; display: flex; align-items: baseline; gap: 8px; }
        .mp-setup-price small { font: 500 12px/1 var(--f-sans); font-style: normal; color: var(--muted); }
        .mp-setup-plus { margin: 0; font: 500 11.5px/1.4 var(--f-mono); letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
        .mp-ticks { list-style: none; margin: 20px 0 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
        .mp-setup-plus + .mp-ticks { margin-top: 12px; }
        .mp-ticks li { display: flex; gap: 12px; align-items: flex-start; font-size: 15px; line-height: 1.5; color: var(--ink-2); }
        .mp-ticks li::before {
          content: ""; flex-shrink: 0; width: 20px; height: 20px; margin-top: 1px; border-radius: 50%;
          background: var(--accent);
          -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12l5 5L20 6'/%3E%3C/svg%3E") center / 12px no-repeat, linear-gradient(#000 0 0);
          -webkit-mask-composite: xor; mask-composite: exclude;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12l5 5L20 6'/%3E%3C/svg%3E") center / 12px no-repeat, linear-gradient(#000 0 0);
        }

        /* ---- D. Add-ons ---- */
        .mp-addons { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
        @media (max-width: 860px) { .mp-addons { grid-template-columns: 1fr; } }
        .mp-addon { background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius-xl); padding: 28px; }
        html.dark .mp-addon { background: var(--paper-3); }
        .mp-addon-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
        .mp-addon h3 { font-size: 19px; letter-spacing: -0.015em; max-width: 22ch; }
        .mp-addon-price { font-family: var(--f-serif); font-style: italic; font-size: 30px; line-height: 1; letter-spacing: -0.02em; display: flex; align-items: baseline; gap: 8px; white-space: nowrap; }
        .mp-addon-price small { font: 500 12px/1 var(--f-sans); font-style: normal; color: var(--muted); }
        .mp-addon p { margin: 16px 0 0; font-size: 14.5px; line-height: 1.6; color: var(--muted); }

        /* ---- E. Ready ---- */
        .mp-ready { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 18px 32px; }
        @media (max-width: 760px) { .mp-ready { grid-template-columns: 1fr; } }
        .mp-ready li { display: flex; gap: 14px; align-items: flex-start; padding: 18px 0; border-top: 1px solid var(--line); }
        .mp-ready-n { flex-shrink: 0; width: 30px; height: 30px; border-radius: 50%; background: var(--paper-2); color: var(--ink); display: grid; place-items: center; font: 500 12px/1 var(--f-mono); }
        .mp-ready h4 { font-size: 16px; font-weight: 500; letter-spacing: -0.01em; margin: 4px 0 6px; }
        .mp-ready p { margin: 0; font-size: 14.5px; line-height: 1.55; color: var(--muted); }

        /* ---- F. Honest ---- */
        .mp-honest {
          display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.4fr); gap: 40px;
          background: var(--paper); border: 1px solid var(--line); border-left: 4px solid var(--accent);
          border-radius: var(--radius-xl); padding: 40px 44px;
        }
        html.dark .mp-honest { background: var(--paper-3); }
        @media (max-width: 860px) { .mp-honest { grid-template-columns: 1fr; gap: 20px; padding: 28px 24px; border-radius: var(--radius-lg); } }
        .mp-honest-head h2 { margin-top: 12px; font-size: clamp(26px, 3vw, 36px); letter-spacing: -0.03em; line-height: 1.05; }
        .mp-honest-body p { margin: 0; font-size: 15.5px; line-height: 1.62; color: var(--ink-2); }
        .mp-honest-body p + p { margin-top: 14px; }
        .mp-honest-body a { color: var(--ink); }

        /* ---- G. Billing ---- */
        .mp-facts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
        @media (max-width: 900px) { .mp-facts { grid-template-columns: 1fr 1fr; } }
        @media (max-width: 600px) { .mp-facts { grid-template-columns: 1fr; } }
        .mp-fact { background: var(--paper-2); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 24px 22px; }
        html.dark .mp-fact { background: var(--paper-3); }
        .mp-fact h4 { font-size: 16px; font-weight: 500; letter-spacing: -0.01em; margin: 0 0 8px; }
        .mp-fact p { margin: 0; font-size: 14.5px; line-height: 1.58; color: var(--muted); }
        .mp-foot { margin: 22px 0 0; font-size: 13.5px; line-height: 1.6; color: var(--muted); max-width: 76ch; }
        .mp-foot a { color: var(--ink); }

        /* ---- The disclosure ---- */
        .mp-deep { padding: 0 0 24px; }
        .mp-deep-btn {
          appearance: none; width: 100%; cursor: pointer; text-align: left;
          display: flex; align-items: center; justify-content: space-between; gap: 16px;
          background: var(--paper-2); border: 1px solid var(--line); border-radius: var(--radius-lg);
          padding: 22px 24px; color: var(--ink); font-family: var(--f-sans);
          transition: border-color .15s ease;
        }
        html.dark .mp-deep-btn { background: var(--paper-3); }
        .mp-deep-btn:hover { border-color: var(--ink); }
        .mp-deep-btn b { display: block; font-size: 17px; font-weight: 500; letter-spacing: -0.01em; }
        .mp-deep-sub { display: block; margin-top: 4px; font-size: 13.5px; color: var(--muted); }
        .mp-deep-i { flex-shrink: 0; width: 36px; height: 36px; border-radius: 50%; border: 1px solid var(--line-2); display: grid; place-items: center; transition: transform .25s ease, background .2s; }
        .mp-deep-i.open { transform: rotate(45deg); background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
        #mp-deep-body { margin-top: 8px; }

        /* ---- Tables (shared) ---- */
        .mp-tablewrap {
          overflow-x: auto; -webkit-overflow-scrolling: touch;
          border: 1px solid var(--line); border-radius: var(--radius-lg);
          background: var(--paper); box-shadow: var(--shadow-sm);
        }
        .mp-table { width: 100%; border-collapse: collapse; font-size: 14px; }
        .mp-table-rates { min-width: 700px; }
        .mp-table-features { min-width: 1080px; }
        .mp-table-example { min-width: 620px; }
        /* Column widths are set on the header cells, not with max-width on the
           data cells: max-width is ignored in an auto-layout table, so without
           these the feature column eats the rate columns it exists to compare. */
        .mp-table-rates thead th:nth-child(1) { width: 28%; }
        .mp-table-rates thead th:nth-child(2) { width: 28%; }
        .mp-table-rates thead th:nth-child(3) { width: 18%; }
        .mp-table-rates thead th:nth-child(4) { width: 26%; }
        .mp-table-features thead th:nth-child(1) { width: 24%; }
        .mp-table-features thead th:nth-child(2) { width: 20%; }
        .mp-table-features thead th:nth-child(3) { width: 11%; }
        .mp-table-features thead th:nth-child(4) { width: 15%; }
        .mp-table-features thead th:nth-child(5) { width: 18%; }
        .mp-table-features thead th:nth-child(6) { width: 12%; }
        .mp-table-example thead th:nth-child(1) { width: 52%; }
        .mp-table-example thead th:nth-child(2) { width: 14%; }
        .mp-table-example thead th:nth-child(3) { width: 14%; }
        .mp-table-example thead th:nth-child(4) { width: 20%; }
        .mp-table th, .mp-table td {
          text-align: left; vertical-align: top;
          padding: 13px 16px; border-bottom: 1px solid var(--line);
        }
        .mp-table thead th {
          font: 600 10.5px/1.3 var(--f-mono); letter-spacing: .1em; text-transform: uppercase;
          color: var(--muted); background: var(--paper-2); white-space: nowrap;
        }
        .mp-table tbody th[scope="row"] { font-weight: 500; color: var(--ink); max-width: 36ch; }
        .mp-table > tbody:last-of-type > tr:last-child > * { border-bottom: none; }
        .mp-table tfoot th, .mp-table tfoot td { background: var(--paper-2); border-bottom: none; font-weight: 500; }
        .mp-table tfoot tr:first-child > * { border-top: 1px solid var(--line-2); }
        .mp-group th {
          background: var(--paper-3); color: var(--ink);
          font: 600 10.5px/1.3 var(--f-mono); letter-spacing: .1em; text-transform: uppercase;
        }
        .mp-dim { color: var(--muted); max-width: 30ch; }
        .mp-num { font-family: var(--f-mono); font-size: 12.5px; max-width: 28ch; }
        .mp-strong { color: var(--ink); font-weight: 500; }
        .mp-cellnote {
          display: block; margin-top: 6px; max-width: 30ch;
          font: 400 11.5px/1.45 var(--f-sans); color: var(--muted);
        }
        /* Only shown at the widths where the table actually overflows its
           wrapper — a "scroll sideways" prompt on a table that fits is noise. */
        .mp-scrollhint {
          display: none; margin: 10px 2px 0;
          font: 500 10.5px/1.4 var(--f-mono); letter-spacing: .06em;
          text-transform: uppercase; color: var(--muted-2);
        }
        /* Under 720px the rates and example tables give way to cards (below),
           so the hint only has the narrow band where the table still shows
           and overflows. */
        @media (min-width: 720px) and (max-width: 740px) { .mp-scrollhint.w700 { display: block; } }

        /* ---- D + G on handsets: the rate and example tables become cards ---- */
        .mp-rcards, .mp-ecards { display: none; }
        @media (max-width: 719px) {
          .mp-rtable-wrap, .mp-etable-wrap { display: none; }
          .mp-rcards, .mp-ecards { display: block; }
        }
        .mp-rcards .mp-fcard + .mp-fcard, .mp-ecards .mp-fcard + .mp-fcard { margin-top: 10px; }
        .mp-ecard-sum { margin: 10px 0 0; font: 400 13px/1.5 var(--f-mono); color: var(--muted); }
        .mp-ecard-sum strong { color: var(--ink); font-weight: 500; }
        .mp-ecard-total { background: var(--paper-2); }
        .mp-ecard-total .mp-fcard-lines { margin-top: 0; }

        /* ---- D. Meta's rates ---- */
        .mp-notes { list-style: none; margin: 26px 0 0; padding: 0; display: grid; gap: 14px; }
        .mp-notes li {
          position: relative; padding-left: 20px; max-width: 78ch;
          font-size: 14px; line-height: 1.62; color: var(--muted);
        }
        .mp-notes li::before {
          content: ""; position: absolute; left: 0; top: 9px;
          width: 7px; height: 7px; border-radius: 50%; background: var(--accent);
        }
        .mp-rough { margin-top: 30px; }
        .mp-minitable { border-collapse: collapse; font-size: 14px; }
        .mp-minitable caption {
          text-align: left; padding-bottom: 10px;
          font: 600 10.5px/1.3 var(--f-mono); letter-spacing: .1em;
          text-transform: uppercase; color: var(--muted);
        }
        .mp-minitable th {
          text-align: left; font-weight: 400; color: var(--muted);
          padding: 10px 28px 10px 0; border-bottom: 1px solid var(--line);
        }
        .mp-minitable td { padding: 10px 0; border-bottom: 1px solid var(--line); white-space: nowrap; }
        .mp-minitable tr:last-child > * { border-bottom: none; }

        /* ---- Status pills ---- */
        .mp-pillwrap { display: inline-flex; flex-direction: column; align-items: flex-start; gap: 6px; }
        .mp-pill {
          font: 600 10px/1 var(--f-mono); letter-spacing: .04em; text-transform: uppercase;
          padding: 6px 10px; border-radius: 999px; white-space: nowrap;
        }
        .mp-pill.same { background: var(--paper-3); color: var(--muted); }
        .mp-pill.new { background: var(--ink); color: var(--paper); }
        .mp-pill.mint { background: var(--accent-soft); color: var(--accent-ink); }
        /* html.dark flips --accent-soft to a dark green but leaves --accent-ink
           dark too, so the mint pill needs its own ink there or it vanishes. */
        html.dark .mp-pill.mint { color: var(--accent); }
        .mp-pill-note { max-width: 17ch; font-size: 11px; line-height: 1.35; color: var(--muted); }

        /* ---- E. 1 October 2026 ---- */
        .mp-oct {
          background: var(--ink); color: var(--paper);
          border-radius: var(--radius-xl); padding: 44px 48px 40px;
        }
        @media (max-width: 760px) { .mp-oct { padding: 30px 22px 26px; border-radius: var(--radius-lg); } }
        .mp-oct-eyebrow {
          font: 500 10.5px/1.6 var(--f-mono); letter-spacing: .1em; text-transform: uppercase;
          color: color-mix(in oklab, var(--paper) 58%, var(--ink));
        }
        .mp-oct-title {
          margin-top: 14px; max-width: 18ch; color: var(--paper);
          font-size: clamp(28px, 3.4vw, 44px); line-height: 1.04; letter-spacing: -.03em;
        }
        @media (max-width: 768px) { .mp-oct-title { font-size: clamp(24px, 7vw, 32px); } }
        .mp-oct-list { list-style: none; margin: 32px 0 0; padding: 0; display: grid; gap: 22px; }
        .mp-oct-item { display: flex; gap: 16px; align-items: flex-start; }
        .mp-oct-num {
          flex-shrink: 0; width: 26px; height: 26px; margin-top: 2px;
          border-radius: 50%; display: grid; place-items: center;
          background: color-mix(in oklab, var(--paper) 12%, transparent);
          color: var(--accent); font: 600 11px/1 var(--f-mono);
        }
        .mp-oct-body {
          margin: 0; max-width: 74ch; font-size: 15px; line-height: 1.62;
          color: color-mix(in oklab, var(--paper) 72%, var(--ink));
        }
        .mp-oct-body strong { color: var(--paper); font-weight: 500; }
        .mp-oct-means {
          margin: 9px 0 0; max-width: 70ch; font-size: 13.5px; line-height: 1.55;
          color: color-mix(in oklab, var(--paper) 62%, var(--ink));
        }
        .mp-oct-means em {
          font: 600 10.5px/1 var(--f-mono); font-style: normal;
          letter-spacing: .08em; text-transform: uppercase; color: var(--accent);
        }
        .mp-oct-side {
          margin: 32px 0 0; padding-top: 22px; max-width: 84ch;
          border-top: 1px solid color-mix(in oklab, var(--paper) 14%, transparent);
          font-size: 13px; line-height: 1.6;
          color: color-mix(in oklab, var(--paper) 58%, var(--ink));
        }

        /* ---- F. Feature by feature ----
           The table is the desktop read; under 720px the same rows render as
           labelled cards, because a six-column table on a 375px handset is a
           table nobody reads — and the page must never scroll sideways. */
        .mp-fcards { display: none; }
        @media (max-width: 719px) {
          .mp-ftable-wrap { display: none; }
          .mp-fcards { display: block; }
        }
        .mp-fgroup + .mp-fgroup { margin-top: 28px; }
        .mp-fgroup-title {
          margin: 0 0 10px; font: 600 10.5px/1.4 var(--f-mono);
          letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
        }
        .mp-fcard {
          background: var(--paper); border: 1px solid var(--line);
          border-radius: var(--radius); padding: 16px 16px 14px; box-shadow: var(--shadow-sm);
        }
        .mp-fcard + .mp-fcard { margin-top: 10px; }
        .mp-fcard-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
        .mp-fcard-name { font-size: 14.5px; font-weight: 500; line-height: 1.4; }
        .mp-fcard-lines {
          margin: 13px 0 0; display: grid;
          grid-template-columns: minmax(92px, auto) 1fr; gap: 7px 14px;
        }
        .mp-fcard-lines dt {
          font: 500 10px/1.5 var(--f-mono); letter-spacing: .06em;
          text-transform: uppercase; color: var(--muted-2);
        }
        .mp-fcard-lines dd { margin: 0; font-size: 13px; line-height: 1.5; color: var(--muted); }
        .mp-fcard-lines dd.mp-num { color: var(--ink); max-width: none; }

        /* ---- G. A month, worked out ---- */
        .mp-newtag {
          display: inline-block; margin-left: 8px; padding: 4px 7px; vertical-align: 2px;
          border-radius: 999px; background: var(--accent-soft); color: var(--accent-ink);
          font: 600 9.5px/1 var(--f-mono); letter-spacing: .06em; text-transform: uppercase;
          white-space: nowrap;
        }
        html.dark .mp-newtag { color: var(--accent); }
        .mp-said { margin: 18px 0 0; max-width: 80ch; font-size: 14.5px; line-height: 1.65; color: var(--muted); }
        .mp-said-last { color: var(--ink); }

        /* ---- H. Questions ----
           The homepage accordion caps the answer at 400px; these answers are
           longer, and a clipped answer on a money page is worse than no page. */
        .mp-faq .faq-q { font-size: 17px; }
        .mp-faq .faq.open .faq-a { max-height: 900px; }
        .mp-faq .faq:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-sm); }

        /* ---- I. Sources ---- */
        .mp-sources-block { padding: 56px 0 72px; }
        .mp-sources-head {
          font: 600 10.5px/1.3 var(--f-mono); letter-spacing: .1em;
          text-transform: uppercase; color: var(--muted);
        }
        .mp-sources { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 10px; }
        .mp-sources li { max-width: 92ch; font: 400 12.5px/1.6 var(--f-mono); color: var(--muted); overflow-wrap: anywhere; }
        .mp-sources a { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--line-2); }
        .mp-sources a:hover { border-bottom-color: var(--ink); }
        .mp-sources-note { color: var(--muted-2); }


        @media (max-width: 768px) {
          .mp-table th, .mp-table td { padding: 11px 13px; }
          .mp-sources-block { padding: 40px 0 56px; }
          .mp-setup-card, .mp-addon { padding: 22px 20px; }
        }
      `}</style>
    </>
  );
}
window.PricingPage = PricingPage;
