/* plans-card.css: the "Plans" card. ONE copy, used by the homepage hero
   (index.html .intro-card) and the shared buy block (partials/buy-block.html,
   on /benchmark, /learn, /bakeoff and /how-to-redact). Moved out of index.html
   2026-10-04; each var() carries a fallback so the card renders the same on
   the bake-off report, which has its own smaller token set.
   Since 2026-10-14 (owner) the card also carries the INLINE BUY: each plan
   column is a button that opens that plan's buy panel in the card. The same
   panel treatment (smooth open, rings drawn inside the field) applies to the
   homepage's §9 pricing cards, which load this file with the hero. */
  /* ---- The card: PLANS eyebrow, the two plan columns, Buy Cover, trial ---- */
  .intro-card-eyebrow {
    /* MATCHES .card-pricing .plan-name (section 9) EXACTLY — display face,
       0.75rem, 700, 0.12em, uppercase, primary. That is this page's label
       style for a label INSIDE a pricing card. The section-level .eyebrow
       token in DESIGN.md (body face, 0.8125rem, 600, 0.06em) is a different
       component: it labels a section against the page ground, not a row inside
       a card. Keep this in lockstep with .plan-name. */
    font-family: var(--font-display, inherit);
    font-size: 0.75rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
    /* 0.875rem below it (was 0.5rem over the old one-line price list): the
       columns under it open with their own small plan name, so the label
       needs the extra air to read as the heading of both. */
    color: var(--color-primary-text, #2F6FD0); margin: 0 0 0.875rem; text-align: left;
  }
  /* ORDER (2026-08-06, owner; columns 2026-10-14): eyebrow, the two plans,
     Buy Cover, trial link. The buy panels sit between the plans and Buy Cover,
     so an open one reads as the next step of the plan above it. */

  .intro-card {
    position: relative;
    background: var(--bg-surface, #fff);
    border: 1px solid var(--border-subtle, rgba(0,0,0,0.08));
    border-radius: 18px;
    /* 8-PT GRID (DESIGN.md spacing scale). 32px top / 24px sides / 24px bottom:
       spacing.6 and spacing.5, mirroring how .card-pricing runs a heavier top
       than bottom (40/30/28 on a 390px card). The old 30px top was off-grid.
       Side padding 1.5rem (24px), trimmed from 1.75rem: the approved G2 mockup
       runs 20px sides on a 327px card, and every 1px of side padding costs 2px
       of card width. 24px splits the difference — it buys back 8px of width
       while staying close to the 1.875rem sides of the §9 pricing cards. */
    padding: 2rem 1.5rem 1.5rem;
    /* Same recipe as .card-pricing: float-strong, plus the warm 0.5px contact
       hairline in light mode (rule below). This card sits on the same cream
       ground as the section-9 pricing cards and should catch light the same
       way; --shadow-float alone made it sit flatter than they do. */
    box-shadow: var(--shadow-float-strong, 0 24px 48px -12px rgba(0,0,0,0.16));
    /* 324px = the approved-mockup width (index.html .intro-grid says how that
       number was derived). max-width caps it below ~372px viewports so the
       fixed width can never force horizontal scroll on a phone; it narrows
       instead, and the plan columns step down with it (the container query
       at the end of the plan rules), so nothing wraps at 320px (222px of
       content box). */
    width: 324px;
    max-width: 100%;
    overflow: hidden;
    /* A size container, so the narrow step follows the card's own width, not
       a guessed viewport breakpoint. The width is set above, never by the
       content, which is what inline-size containment requires. */
    container: plans-card / inline-size;
    /* LEFT, matching .card-pricing in §9 (the page's other pricing surface):
       card copy left-aligns and only the full-width button and the trial link
       under it centre themselves. Was `center`, which centred the eyebrow and
       the price line against every other card on the page. */
    text-align: left;
    flex-shrink: 0;
  }
  /* Warm edge stroke (light only) — the identical recipe .card-pricing uses,
     so the two pricing surfaces on this page have the same edge. */
  [data-theme="light"] .intro-card {
    border: 1px solid rgba(98,93,75,0.175);
    box-shadow: var(--shadow-float-strong, 0 24px 48px -12px rgba(0,0,0,0.16)), 0 0.5px 0 rgba(98,93,75,0.195);
  }
  .intro-card .btn { width: 100%; }

  /* .intro-card-buy = the hero's own Buy CTA, and ONLY it. The class exists
     because this element can no longer be addressed as `[data-buy-trigger]`
     (it is a plain <a href="#pricing"> now) and MUST NOT be addressed as
     `.intro-card .btn-primary` either: the trial email-capture panel injects
     its own `.btn.btn-primary` submit button and download link INSIDE this same
     card, so that selector would silently capture them too (it did, in the
     first cut of this change: the open panel's own "Download Cover" submit
     button was being display:none'd by the "one question at a time" rule).
     line-height: normal is what makes an <a class="btn"> render the SAME PILL
     as a <button class="btn">. A <button> gets `line-height: normal` from the
     UA sheet (.btn never sets one); an <a> inherits the body's 1.6, i.e. 24px
     at this 15px size. When the hero CTA became an anchor that alone made it
     52px tall against the §9 "Buy Cover · $39" buttons' 45.5px — a 6.5px
     mismatch between two pills that are meant to read as siblings. Restating
     `normal` resolves it to the identical 17.5px.
     white-space: nowrap keeps the short label off a second line in this narrow
     card (it inherited this from the [data-buy-trigger] rule above). */
  .intro-card .intro-card-buy { line-height: normal; white-space: nowrap; }


  /* ---- The plan columns (owner 2026-10-14) ----
     Personal | Business side by side, two plain equal columns with the same
     treatment, each a BUTTON (data-buy-trigger) that opens its own buy panel
     in this card through site-chrome.js's ordinary wiring. A soft grey tint
     on hover, no stroke, no fill at rest: spacing does the separating. The
     annual amounts are site_prices.py markers; never hand-edit them. No
     "a month" restatement under them (owner removed it). */
  .intro-card .icp-plans {
    position: relative;
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: 1rem;
    margin: 0 0 1rem;
  }
  /* The tile reaches 6px / 8px past its text (negative margin), so the hover
     tint has room without moving the text off the card's left edge. */
  .intro-card .icp-pick {
    all: unset;
    box-sizing: border-box; display: block; min-width: 0; cursor: pointer;
    text-align: left;
    border-radius: 10px; padding: 6px 8px; margin: -6px -8px;
    transition: background-color 0.15s ease, transform 0.38s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.22s ease;
  }
  .intro-card .icp-pick:hover { background: rgba(26, 28, 30, 0.045); }
  [data-theme="dark"] .intro-card .icp-pick:hover { background: rgba(255, 255, 255, 0.06); }
  .intro-card .icp-pick:focus-visible { outline: 2px solid var(--color-primary-base, #4A8FF3); outline-offset: 1px; }
  .intro-card .icp-pick > span { display: block; }
  .intro-card .icp-name {
    font-size: 0.8125rem; font-weight: 500; line-height: 1.3;
    color: var(--text-secondary, #55595F);
  }
  /* "$99" bold in ink, "/yr" in the caption grey, the amount one size up so a
     column reads at a glance. Tabular figures keep the units at one x. */
  .intro-card .icp-price {
    margin-top: 0.25rem; white-space: nowrap; line-height: 1.15;
    font-size: 0.8125rem; font-weight: 500;
    color: var(--text-secondary, #55595F);
  }
  .intro-card .icp-amt {
    font-family: var(--font-display, inherit);
    font-size: 1.375rem; font-weight: 700; letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary, #1A1C1E);
  }

  /* ---- Buying: a plan's panel is open (plans-card.js sets data-buying) ----
     The chosen plan keeps the grey tile, in the LEFT slot: Business slides
     over (--icp-shift, measured), Personal fades. site-chrome.css hides a
     card's [data-buy-trigger]s while any panel is open; the columns are
     exempt, so they stay as the question's own header. */
  .intro-card:has(.email-capture.is-open) .icp-plans .icp-pick { display: block; }
  .intro-card[data-buying] .icp-pick[aria-expanded="true"] {
    background: rgba(26, 28, 30, 0.045); justify-self: start; padding-right: 14px;
  }
  [data-theme="dark"] .intro-card[data-buying] .icp-pick[aria-expanded="true"] { background: rgba(255, 255, 255, 0.06); }
  .intro-card[data-buying] .icp-pick[aria-expanded="false"] { opacity: 0; pointer-events: none; }
  .intro-card[data-buying="business"] .icp-pick[data-pick="business"] { transform: translateX(var(--icp-shift, 0px)); }
  /* The right slot: the seat count belongs to Business, so it sits 8px off
     the tile as one group (--icp-side-left, measured); Change is its own
     action, far right, and goes back to both plans. */
  .intro-card .icp-side {
    position: absolute; left: var(--icp-side-left, auto); right: 0; top: 50%; transform: translateY(-50%);
    display: flex; align-items: center; justify-content: space-between;
    opacity: 0; pointer-events: none; transition: opacity 0.22s ease 0.12s;
  }
  .intro-card[data-buying] .icp-side { opacity: 1; pointer-events: auto; }
  /* Too narrow for both beside the tile (plans-card.js measures it): the
     right slot takes its own row under the tile, picker left, Change right. */
  .intro-card[data-icp-stacked] .icp-side { position: static; grid-column: 1 / -1; transform: none; margin-top: 10px; }
  .intro-card .icp-change {
    all: unset; margin-left: auto; cursor: pointer;
    font-family: var(--font-body, inherit); font-size: 0.8125rem; font-weight: 500;
    color: var(--color-primary-text, #2F6FD0);
  }
  .intro-card .icp-change:hover { color: var(--color-primary-text-hover, #2A62BC); }
  .intro-card .icp-change:focus-visible { outline: 2px solid var(--color-primary-base, #4A8FF3); outline-offset: 2px; border-radius: 4px; }
  /* Seats (Business only): a soft tinted capsule like the billing toggle's
     track, no outline. checkout reads the FIRST [data-seats-for="business"]
     on the page (site-chrome.js seatsFor); this picker is data-seats-card in
     markup and plans-card.js makes it a [data-seats-for] when it runs, then
     keeps every picker on the page at one value, so this one and §9's always
     agree (and with no script, §9's is the one checkout reads). */
  .intro-card .icp-seats { display: none; position: relative; }
  .intro-card[data-buying="business"] .icp-seats { display: block; }
  .intro-card .icp-seats select {
    -webkit-appearance: none; appearance: none; border: 0; margin: 0; cursor: pointer;
    font: 500 12.5px/18px var(--font-body, -apple-system, BlinkMacSystemFont, sans-serif);
    color: var(--text-primary, #1A1C1E); background: rgba(26, 28, 30, 0.055); border-radius: 999px;
    padding: 4px 22px 4px 10px; transition: background-color 0.15s ease;
  }
  .intro-card .icp-seats select:hover { background: rgba(26, 28, 30, 0.085); }
  .intro-card .icp-seats select:focus-visible { outline: 2px solid var(--color-primary-base, #4A8FF3); outline-offset: 1px; }
  .intro-card .icp-seats::after {
    content: ""; position: absolute; right: 9px; top: 50%; width: 5px; height: 5px; margin-top: -4px;
    border-right: 1.5px solid #6E6E73; border-bottom: 1.5px solid #6E6E73;
    transform: rotate(45deg); pointer-events: none;
  }
  [data-theme="dark"] .intro-card .icp-seats select { background: rgba(255, 255, 255, 0.07); }
  [data-theme="dark"] .intro-card .icp-seats select:hover { background: rgba(255, 255, 255, 0.11); }
  [data-theme="dark"] .intro-card .icp-seats::after { border-color: #A8ADB7; }
  /* NARROW CARD (viewport under 372px; 222px of content at 320). The columns
     and the right slot step down a little so nothing wraps or overlaps:
     measured at 320, the open Business tile, the seat picker (as wide as its
     widest option, "20 seats") and Change need 247px at full size against
     230px of row; here they fit with about 7px between picker and Change.
     plans-card.js stacks the right slot only below 6px (MIN_GAP). */
  @container plans-card (max-width: 273px) {
    .intro-card .icp-plans { column-gap: 0.5rem; }
    .intro-card .icp-amt { font-size: 1.125rem; }
    .intro-card .icp-price { font-size: 0.75rem; }
    .intro-card[data-buying] .icp-pick[aria-expanded="true"] { padding-right: 6px; }
    .intro-card .icp-seats select { font-size: 11.5px; line-height: 17px; padding: 3px 14px 3px 7px; }
    .intro-card .icp-seats::after { right: 5px; width: 4px; height: 4px; margin-top: -3px; }
    .intro-card .icp-change { font-size: 0.72rem; }
  }
  @media (prefers-reduced-motion: reduce) {
    .intro-card .icp-pick, .intro-card .icp-side { transition: none; }
  }

  /* The hero Buy CTA is an <a>, not a [data-buy-trigger], so site-chrome.css's
     shared "hide this card's CTAs while a form is open" rule does not catch
     it. Keep the behaviour explicitly: with a form open the card asks exactly
     one question. Must target .intro-card-buy, NOT .btn-primary: the open
     panel's own submit/download buttons are .btn-primary inside this card.
     (See the .intro-card-buy rule above.) */
  .intro-card:has(.email-capture.is-open) .intro-card-buy { display: none; }
  /* No override: the trial link keeps the shared .trial-link margin-top of
     0.7rem, which is exactly what the section-9 cards use under their own Buy
     buttons. */

  /* ---- Inline panels: this card and the §9 pricing cards (owner 2026-10-14) ----
     Not the nav dropdown (.ec-nav) and not the footer signup, which keep
     site-chrome.css's own rules.
     SMOOTH OPEN. site-chrome.css reveals a panel by max-height 0 -> 400px,
     which reaches a ~110px form in a tenth of the time and read as a jump.
     This animates the REAL height (grid rows 0fr -> 1fr) and slides the
     content in with it. A closed panel takes no space and no margin, so a
     closed sibling never doubles the gap above an open one, and it is
     visibility:hidden once collapsed, so its field is not a Tab stop. */
  :is(.intro-card, .card-pricing) .email-capture:not(.ec-nav) {
    max-height: none; display: grid; grid-template-rows: 0fr;
    padding-top: 0; margin-top: 0; visibility: hidden;
    transition: grid-template-rows 0.46s cubic-bezier(0.22, 0.8, 0.24, 1), opacity 0.3s ease, visibility 0s linear 0.46s;
  }
  :is(.intro-card, .card-pricing) .email-capture:not(.ec-nav).is-open {
    grid-template-rows: 1fr; margin-top: 0; visibility: visible;
    transition: grid-template-rows 0.46s cubic-bezier(0.22, 0.8, 0.24, 1), opacity 0.3s ease, visibility 0s;
  }
  :is(.intro-card, .card-pricing) .email-capture:not(.ec-nav) > .ec-inner {
    min-height: 0; overflow: hidden; padding-top: 0;
    transform: translateY(-4px); transition: transform 0.46s cubic-bezier(0.22, 0.8, 0.24, 1);
  }
  :is(.intro-card, .card-pricing) .email-capture:not(.ec-nav).is-open > .ec-inner { transform: none; }
  /* The sentence sits close to the field it describes. */
  :is(.intro-card, .card-pricing) .email-capture .ec-prompt { margin: 0 0 6px; }
  :is(.intro-card, .card-pricing) .email-capture .ec-s { margin-top: 0; }
  /* The requirement line is one line wherever it fits (274px and up). On a
     narrower card it wraps: kept on one line it ran ~37px past a 320px
     phone's panel and was cut off mid-word ("or in your b"). */
  :is(.intro-card, .card-pricing) .email-capture .sysreq { white-space: normal; }
  /* The focus ring is drawn INSIDE the field, so the panel's clip never cuts
     it on the left and it ends exactly where the button begins. */
  :is(.intro-card, .card-pricing) .email-capture .ec-input:focus {
    border-color: var(--color-primary-base, #4A8FF3);
    box-shadow: inset 0 0 0 1px var(--color-primary-base, #4A8FF3), inset 0 0 0 4px rgba(74, 143, 243, 0.10);
  }
  /* The error ring follows it inside, and wins over focus, so a refused
     address always reads red. */
  :is(.intro-card, .card-pricing) .email-capture.is-error .ec-input,
  :is(.intro-card, .card-pricing) .email-capture.is-error .ec-input:focus {
    border-color: var(--status-critical, #E5484D);
    box-shadow: inset 0 0 0 1px var(--status-critical, #E5484D), inset 0 0 0 4px rgba(229, 72, 77, 0.10);
  }
  /* No glow and no lift on the panel's buttons (Continue, Download, and the
     done state's button): the panel clips whatever reaches past its edge, and
     a glow cut off by a straight line reads as a rendering fault. Keyboard
     focus is drawn inside the button for the same reason. */
  :is(.intro-card, .card-pricing) .email-capture .ec-submit,
  :is(.intro-card, .card-pricing) .email-capture .ec-submit:is(:hover, :focus, :active),
  :is(.intro-card, .card-pricing) .email-capture .ec-done .btn,
  :is(.intro-card, .card-pricing) .email-capture .ec-done .btn:is(:hover, :focus, :active) { box-shadow: none; transform: none; }
  :is(.intro-card, .card-pricing) .email-capture .ec-submit:focus-visible,
  :is(.intro-card, .card-pricing) .email-capture .ec-done .btn:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.9); outline-offset: -5px; }
  @media (prefers-reduced-motion: reduce) {
    :is(.intro-card, .card-pricing) .email-capture:not(.ec-nav),
    :is(.intro-card, .card-pricing) .email-capture:not(.ec-nav).is-open,
    :is(.intro-card, .card-pricing) .email-capture:not(.ec-nav) > .ec-inner { transition: none; }
  }
  @media (max-width: 760px) {
    .intro-card { margin: 0 auto; }
  }

  /* ---- Billing toggle: Yearly / Monthly (dev/tools/site_prices.py --monthly) ----
     ONE state for the whole page, on <html data-billing>, set by plans-card.js.
     MONTHLY is the default (owner 2026-11-11): no attribute (script not run
     yet) reads as Monthly, so the first paint already shows the price
     plans-card.js is about to select. The checkout learns the period from
     ?billing=monthly, which plans-card.js writes on load. */
  :root:not([data-billing="year"]) .bill-y,
  :root[data-billing="year"] .bill-m { display: none !important; }
  /* SOFT (owner 2026-10-14: "too many strokes", no hard edges nested in hard
     edges): no border on the track, no ring on the selected side (a soft lift
     only), capsules, one weight in both states so nothing shifts. */
  .bill-toggle {
    display: inline-flex; gap: 2px; padding: 4px;
    border-radius: 999px;
    background: rgba(26, 28, 30, 0.055);
  }
  [data-theme="dark"] .bill-toggle { background: rgba(255, 255, 255, 0.07); }
  .bill-toggle label { position: relative; display: inline-flex; cursor: pointer; }
  .bill-toggle input {
    position: absolute; inset: 0; width: 100%; height: 100%;
    margin: 0; opacity: 0; cursor: pointer;
  }
  .bill-toggle .bill-opt {
    display: inline-flex; align-items: center; gap: 0.45rem;
    padding: 0.48rem 1.1rem; border-radius: 999px;
    font-family: var(--font-body, inherit);
    font-size: 0.9063rem; font-weight: 500; line-height: 1.2; white-space: nowrap;
    color: var(--text-secondary, #55595F);
    transition: background-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
  }
  .bill-toggle label:hover .bill-opt { color: var(--text-primary, #1A1C1E); }
  /* The selected side is keyed on <html data-billing>, exactly what the
     prices are keyed on (above), not on :checked: a radio the browser
     restored, or one with no script behind it, cannot light up the side whose
     prices are not on show. plans-card.js keeps :checked in step for the
     keyboard. */
  :root[data-billing="year"] .bill-toggle input[value="year"] + .bill-opt,
  :root:not([data-billing="year"]) .bill-toggle input[value="month"] + .bill-opt {
    background: #FFFFFF; color: var(--text-primary, #1A1C1E);
    box-shadow: 0 1px 3px rgba(14, 20, 30, 0.10), 0 2px 8px -2px rgba(14, 20, 30, 0.10);
  }
  [data-theme="dark"][data-billing="year"] .bill-toggle input[value="year"] + .bill-opt,
  [data-theme="dark"]:not([data-billing="year"]) .bill-toggle input[value="month"] + .bill-opt {
    background: var(--bg-surface-raised, #2A2D31); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  }
  .bill-toggle input:focus-visible + .bill-opt {
    outline: 2px solid var(--color-primary-base, #4A8FF3); outline-offset: 1px;
  }
  /* The saving inside Yearly: plain green text, no capsule, so it reads as a
     fact about the price, not a promotion. */
  .bill-toggle .bill-save {
    font-family: var(--font-body, inherit);
    font-size: 0.75rem; font-weight: 600; letter-spacing: 0;
    color: #157A45;
  }
  [data-theme="dark"] .bill-toggle .bill-save { color: #4FD38C; }
  /* §9: each yearly card's own saving, right after its unit, mirroring the
     app's card (TrialWallView, 2026-10-14): plain text in the toggle note's
     green, not a pill, so it never reads as a second money-back badge. */
  .card-pricing .plan-price .plan-save {
    font-family: var(--font-body, inherit);
    font-size: 0.8125rem; font-weight: 600; letter-spacing: 0;
    color: var(--status-success, #2FBF71);
    margin-left: 0.5rem;
  }
  /* §9: the toggle centred above the two cards. */
  .pricing-billing { display: flex; justify-content: center; margin: 0 0 1.75rem; }
  /* Plans card: the toggle shares the PLANS eyebrow's row, and the row takes
     the eyebrow's own space below it. One size down (26px tall) so it does not
     dwarf the eyebrow; the saving is the small green tag inside Yearly. */
  .intro-card .icp-head {
    display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
    margin: 0 0 0.875rem;
  }
  .intro-card .icp-head .intro-card-eyebrow { margin: 0; }
  .bill-toggle.is-compact { padding: 2px; }
  .bill-toggle.is-compact .bill-opt { gap: 0; padding: 3px 10px; font-size: 12px; line-height: 16px; }
  .bill-toggle .bill-tag {
    position: relative; z-index: 1; display: inline-flex; align-items: center;
    margin-left: 4px; color: #1F9D57;
  }
  .bill-toggle .bill-tag svg { display: block; width: 11px; height: 11px; fill: currentColor; }
  .bill-toggle .bill-pct {
    margin-left: 1px; font-size: 10px; font-weight: 600; line-height: 1;
    letter-spacing: -0.02em; font-variant-numeric: proportional-nums;
  }
  [data-theme="dark"] .bill-toggle .bill-tag { color: #4FD38C; }
  @container plans-card (max-width: 273px) {
    .intro-card .bill-toggle.is-compact .bill-opt { padding: 3px 7px; }
  }
  @media (prefers-reduced-motion: reduce) { .bill-toggle .bill-opt { transition: none; } }
