/* Belline — Editorial.
   Eine Richtung, keine Variante der alten. Alles hier ist eine Entscheidung
   gegen etwas Bestehendes, und die Begründung steht dabei, weil "es sieht
   besser aus" in drei Wochen niemandem mehr hilft. */

/* Brand tokens (Direction C) from the one shared source. scripts/build-site.ts
   inlines this file into the built stylesheet, so production makes no extra
   request; served straight from public/ it is a normal import. */
/* Belline brand tokens: "The Bell Button", Apple look (17.09.2026).
   White and light grey grounds, near-black ink, one blue, measured against
   apple.com: the palette, the system type stack, pill buttons, 18px tiles.
   The one source for colour, type, radii, spacing, elevation and focus.
   Imported by public/site.d70ff7a5.css (inlined into it by scripts/build-site.ts)
   and by src/app/globals.css. Change a value here and both follow.
   Contrast ratios are WCAG 2.x, computed; see docs/brand/guidelines.md.

   This file is the ONLY place in the repo where a colour may be written as a
   raw hex. `npm run check:tokens` (scripts/check-tokens.ts) fails the build on
   a literal hex anywhere in public/site.d70ff7a5.css or src/app/globals.css, which is
   what stops a repaint from happening by accident: a later block that sets its
   own `#FFFFFF` cannot silently undo an earlier token, because it cannot be
   written. Two colours that are not ours still live here rather than inline —
   WhatsApp's green, because it is a mark, and absolute white and black,
   because they are structural (see each below). */

:root {
  /* Colour: grounds */
  --bl-ground: #FFFFFF;       /* page ground, cards, inputs. Ink 16.83, text-2 / muted 5.07, blue 4.70, accent-text 5.57 */
  --bl-surface: #F5F5F7;      /* the light grey band, table heads, soft panels. Ink 15.46, text-2 / muted 4.66, accent-text 5.11 (blue 4.31: never small text there) */
  --bl-sunken: #E8E8ED;       /* pressed and sunken fills. Ink 13.78, accent-text 4.56. text-2 / muted only 4.15: never small grey text on it (the app's hover ground is --bl-surface for that reason) */

  /* Colour: text */
  --bl-ink-900: #1D1D1F;      /* ink: headings, primary text, marks. 16.83 on ground, 15.46 on surface */
  --bl-text-2: #6E6E73;       /* body and secondary text. 5.07 on ground, 4.66 on surface, 4.67 on tint */
  --bl-muted: #6E6E73;        /* meta text. The same grey as text-2: Apple's lighter #86868B is 3.62 on white and 3.33 on surface, so it is kept for large or decorative text only */

  /* Colour: accent (Apple blue). Fills, focus; words on blue are white. */
  --bl-blue: #0071E3;         /* primary fill, focus ring. White on it 4.70; as text 4.70 on ground only (4.31 on surface: small text uses accent-text) */
  --bl-blue-hover: #006EDB;   /* hover fill. White on it 4.94. Apple's own #0077ED is lighter and leaves white at 4.32, under AA for 17px text */
  --bl-blue-pressed: #0062C4; /* pressed fill. White on it 5.93 */
  --bl-blue-tint: #F0F6FE;    /* selected rows, current nav, Beta, soft washes. Ink 15.48, accent-text 5.12, muted 4.67 */
  --bl-blue-line: #D2D2D7;    /* the neutral card border and hairlines (Apple's divider grey); decorative, not a text colour (1.51 on white) */
  --bl-blue-lit: #2997FF;     /* blue on dark surfaces. 5.58 on the dark band, 6.96 on black; 4.18 on the dark card: large text or decoration only there */
  --bl-accent-text: #0066CC;  /* the accent as small text and links on any light ground. 5.57 ground, 5.11 surface, 5.12 tint, 4.56 sunken */

  /* Colour: the dark band. The names say navy for history; the values are Apple's near-black. */
  --bl-navy: #1D1D1F;         /* dark band ground. On-navy 15.46, white 16.83 */
  --bl-navy-card: #333336;    /* cards on the band. On-navy 11.57, on-navy-2 4.90, blue-lit 4.18 */
  --bl-on-navy: #F5F5F7;
  --bl-on-navy-2: #A1A1A6;    /* secondary text on dark. 6.54 on the band, 4.90 on the dark card */
  --bl-navy-line: rgba(255, 255, 255, 0.12);

  /* Colour: semantic states, separate from the accent */
  --bl-success: #047857;      /* Available, confirmed. 5.48 on ground, 5.04 on surface */
  --bl-success-tint: #ECFDF5; /* 5.21 under success text */
  --bl-warning: #B45309;      /* deposits due, handover waiting. 5.02 on ground, 4.61 on surface */
  --bl-warning-tint: #FFFBEB; /* 4.84 under warning text */
  --bl-danger: #B91C1C;       /* errors, destructive. 6.47 on ground; white on it 6.47 */
  --bl-danger-tint: #FEF2F2;  /* 5.91 under danger text */

  /* Lines */
  --bl-border: var(--bl-blue-line);
  --bl-border-hover: #AEAEB2;  /* a card's border under the pointer, one step darker than --bl-blue-line (Apple's next grey down); decorative, never a text colour */
  --bl-rule: rgba(0, 0, 0, 0.12);
  --bl-rule-soft: rgba(0, 0, 0, 0.07);
  --bl-rule-strong: rgba(0, 0, 0, 0.18);

  /* Focus ring: blue 2px, offset 2px (4.70 on ground, 4.31 on surface, 4.32 on tint: all above 3:1).
     On dark use white (16.83 / 12.59). */
  --bl-focus-color: var(--bl-blue);
  --bl-focus: 2px solid var(--bl-focus-color);
  --bl-focus-offset: 2px;
  --bl-focus-on-dark: #FFFFFF;

  /* Absolute white and black. Structural, not palette: these are the two
     values that must NOT follow a repaint.

     --bl-white is the colour of words and marks that sit on a coloured fill
     (the blue button, the WhatsApp pill, the dark call bar), and of the halo
     that separates a floating button from the page behind it. If the palette
     changed tomorrow, a label on a blue fill would still have to be white.
     --bl-ground is the separate, *role* token for the page and card ground;
     it happens to be the same value today, and it is the one that would move
     if the site ever grew a dark ground. Use --bl-ground for a ground, and
     --bl-white for ink-on-colour. --bl-black exists for mask and fade
     gradients, where the colour is an alpha channel rather than a colour. */
  --bl-white: #FFFFFF;
  --bl-black: #000000;

  /* WhatsApp's own green, unmodified (founder, 23 Sep 2026): the mark is
     recognised before the words beside it are read, and the same green is used
     on the site, in the app and in the widget, so one channel looks the same
     everywhere. It is a brand mark we do not own, so it is named here rather
     than left loose in two stylesheets.
     The handset stays white because it is the mark, and a mark is not text.
     The words beside it are ink: white on this green is 1.98:1, which the axe
     run catches as a serious contrast failure; ink on it is 8.6:1. */
  --bl-whatsapp: #25D366;
  --bl-whatsapp-mark: var(--bl-white);
  --bl-whatsapp-ink: var(--bl-ink-900);

  /* Instagram's, for the same reason as WhatsApp's above: a brand mark we do
     not own, named here rather than left loose in two stylesheets.

     A gradient and not a colour, because that is how the mark is recognised —
     the four stops are Instagram's own, and they are separate tokens so the
     gradient can be rebuilt wherever it is needed rather than copied as a
     string. `--bl-instagram` is the ring and any single-colour use: the
     magenta in the middle of the gradient, which reads as Instagram where one
     colour has to stand for four.
     The camera stays white because it is the mark, and a mark is not text. */
  --bl-instagram-1: #FFC107;
  --bl-instagram-2: #F44336;
  --bl-instagram-3: #9C27B0;
  --bl-instagram-4: #3F51B5;
  --bl-instagram: #C13584;
  --bl-instagram-mark: var(--bl-white);

  /* States lit for a dark ground: the call bar is near-black, and --bl-success
     / --bl-danger are chosen for light grounds (5.48 and 6.47 on white, but
     under 3:1 on the bar). */
  --bl-success-lit: #6FD6AC;  /* the level meter on the call bar. 9.44 on the band */
  --bl-danger-lit: #E98A80;   /* "End call" on hover. 8.31 on the band */
  --bl-warning-ink: #92400E;  /* warning text on --bl-warning-tint. 6.31 */

  /* Categorical tones: the week view's lanes, one per staff member or
     resource. Hue only — all six are pale enough to carry --bl-ink-900 above
     11:1, because the booking's name is written on top of them. They are a
     set, so they are ordered rather than named for any one meaning. */
  --bl-tone-0: #DCEBFB;
  --bl-tone-1: #D6E4DA;
  --bl-tone-2: #DCE3EE;
  --bl-tone-3: #EEDAD6;
  --bl-tone-4: #E6E0EE;
  --bl-tone-5: #E9E6CF;

  /* Service states on the floor plan. Sequential, not categorical: a table
     warms from waiting through late, then cools once the guest is seated. */
  --bl-state-soon: #DCEBFB;
  --bl-state-due: #F1D9A8;
  --bl-state-late: #EBC0B7;
  --bl-state-arrived: #D8E4F0;
  --bl-state-seated: #CFE3D6;

  /* Code on belline.ai/developers: the two colours its blocks need beyond ink,
     the accent text and the muted grey (tags and comments). Both are for small
     text on --bl-surface, the code block's ground. */
  --bl-code-name: #7B3FA0;    /* attribute names, keywords. 6.3 on surface, 6.8 on ground */
  --bl-code-value: #A1430E;   /* quoted values, strings, numbers. 5.8 on surface, 6.3 on ground */
  --bl-row-alt: #FAFAFC;      /* every other row of a reference table; decorative. Ink 16.2, text-2 4.9 */

  /* Type: two faces, and only two.
     Body is the system stack. On Apple devices it resolves to SF Pro Text;
     everywhere else to Inter (Google Fonts), the closest free match. Measured
     on apple.com: body SF Pro Text 17px/25px at -0.374px, buttons 17px 400.

     Headings are IBM Plex Sans. Until now `display` and `text` named the same
     typeface at two optical sizes — SF Pro Display and SF Pro Text — and off
     Apple hardware both fell back to Inter, so on every Windows PC and Android
     phone a customer actually holds, the product had no display face at all.
     That absence is most of what made the pages read as templated.

     Plex rather than a fourth-party face for one reason worth writing down:
     IBM Plex Mono is already loaded, for booking references and keys. Taking
     the headings from the same family means the product speaks in one
     designer's voice instead of borrowing two, and adds no licence — Plex is
     SIL OFL, like Inter.

     IBM Plex Sans Arabic sits in the same stack rather than behind its own
     token. Font fallback is per glyph, not per element, so an Arabic heading on
     a booking-manage page picks it up with no component knowing which language
     it is rendering — and Google serves it only to a page that draws Arabic,
     because the @font-face carries a unicode-range. */
  --bl-font-display: "IBM Plex Sans", "IBM Plex Sans Arabic", -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --bl-font-text: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Inter", "Helvetica Neue", Arial, sans-serif;
  /* The wordmark is a logo, not a heading, so it has its own token and does not
     move when the display face does. It also cannot: belline-wordmark.svg and
     belline-lockup.svg carry the same stack, and those files are rendered where
     no webfont loads — in email clients, in the og:image, by anything that
     rasterises an SVG outside a browser. Pinned here so the mark is the same
     drawing in all of them. */
  --bl-font-wordmark: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Inter", "Helvetica Neue", Arial, sans-serif;
  --bl-weight-display: 600;
  --bl-weight-heading: 600;
  --bl-weight-button: 400;
  --bl-text-size: 17px;
  --bl-line-body: 1.47;       /* 25px at 17px */
  --bl-track-body: -0.022em;  /* -0.374px at 17px */
  --bl-track-display: -0.015em;
  --bl-track-h1: -0.015em;
  --bl-track-h2: -0.01em;
  --bl-track-label: 0.06em;

  /* Type scale — the dashboard's, which is denser than the marketing site's.
     `--bl-text-size` above is the site's body at 17px and is unchanged.

     There was no scale here, only that one size, and the dashboard's answer
     was to pick a number per element: an audit on 30 September found **24
     distinct font sizes across 665 declarations**, twelve of them inside the
     6px between 10 and 16, and eight different display sizes (20, 22, 24, 25,
     27, 30, 32, 34) used exactly once each. Nobody chose that. It is what
     happens when every screen decides on its own, and it is a large part of
     why the backend reads as less considered than the front end however good
     each individual screen is.

     Eight steps, named for the job rather than the number, because a name is
     what makes a second look wrong. The values are the ones already carrying
     the most weight — 13 and 12.5 alone are 306 of the 665 — so adopting this
     moves the odd sizes onto their neighbours rather than restyling the
     product. The half-points are deliberate and kept where they earn it: at
     this density 12.5 and 13.5 are genuinely different, and rounding them
     together would flatten the hierarchy the screens already have.

     Above 15px the dashboard had no scale at all, only one-offs — 16, 16.5,
     17, 20, 22, 24, 25, 27, 30, 32 and 34, most of them used exactly once.
     Reading each in place on 1 October 2026 showed **two jobs, not eleven
     sizes**:

       · a heading — the page title (25), a setup step's own h1 (32 and 34), a
         section h2 (24), the assistant's opener (30);
       · a figure on a tile — every one of them weight 300, -0.035em and
         tabular-nums, at 20, 22, 27 and 34. The same figure was drawn at
         weight 700 on one screen and 300 on the next.

     So one step for a figure, one for a page title, one for the heading that
     opens a screen, and one for lead text. The first version of this block
     guessed 20 and 28 from single uses before any of them had been read; these
     four are measured. */
  --bl-size-caption: 11px;    /* timestamps, counters, the smallest legible line */
  --bl-size-small: 12.5px;    /* hints under fields, secondary rows */
  --bl-size-body: 13px;       /* the dashboard's default sentence */
  --bl-size-body-lg: 13.5px;  /* a sentence that carries the screen */
  --bl-size-label: 14px;      /* field labels, card titles */
  --bl-size-lead: 15px;       /* a panel's own heading */
  --bl-size-sub: 17px;        /* lead text — and the body size the marketing site reads at */
  --bl-size-stat: 22px;       /* a figure on a tile */
  --bl-size-title: 25px;      /* a page title */
  --bl-size-display: 32px;    /* the heading that opens a screen, and the one headline figure */

  /* Radii */
  --bl-radius-pill: 980px;
  --bl-radius-card: 18px;
  --bl-radius-panel: 14px;
  --bl-radius-input: 12px;

  /* Spacing, 4px base */
  --bl-space-1: 4px;
  --bl-space-2: 8px;
  --bl-space-3: 12px;
  --bl-space-4: 16px;
  --bl-space-5: 24px;
  --bl-space-6: 32px;
  --bl-space-7: 48px;
  --bl-space-8: 64px;

  /* Elevation. Flat by rule; one lift for floating things only (menus, the chat dock). */
  --bl-elev-0: none;
  --bl-elev-float: 0 12px 32px -16px rgba(0, 0, 0, 0.3);

  /* ======================================================================
     COLOUR BY ROLE
     ======================================================================

     Everything above this line names a colour by what it *is* — a blue, a
     grey, a tint. Everything below names one by what it is *for*. The values
     are the same palette; nothing new was mixed. The point is that a
     component asks for a job rather than for a hue, so "this is a warning"
     stops being a judgement made again in every file.

     The audit of 25 September found three bugs of one shape: a green
     "Connected" pill while the page's own probe had failed (F1), a board card
     that lost the list's overdue treatment (F13), projected money styled
     exactly like measured money (F14). Each was fixed by hand because there
     was no warn tone to reach for. Cal.com's token file
     (packages/config/theme/tokens.css) solves it with a small closed
     vocabulary — default/subtle/muted/emphasis for prominence, and
     info/success/attention/error at two shades each for state — and that
     vocabulary is what is copied here
     (docs/ux/calcom-benchmark-2026-09-25.md §5, suggestion 4).

     Two things we did NOT copy, on purpose:

       · Their near-black brand and grayscale austerity. Our buyer is a salon
         owner, not an engineer, and the Belline blue is doing real work on
         the marketing site (benchmark suggestion 18, a recorded refusal).
         What we took is the *discipline* — colour where it means something —
         not the palette.
       · A step for every name in every family. Where our palette has three
         light grounds we define three; inventing a fourth name that repeats
         one of the three would be a token that lies about being a distinct
         step, and that is worse than an absent one. Each family below says
         which steps it has.

     Contrast, measured (WCAG 2.x, computed 26 Sep 2026), is on each line.
     ---------------------------------------------------------------------- */

  /* Grounds, faintest first. Three steps, because we have three.
     `emphasis` is the pressed/sunken fill, not a colour — small grey text
     must not sit on it (4.15:1), which is why hover rows use `subtle`. */
  --bl-bg-default: var(--bl-ground);     /* #FFFFFF — the page, cards, inputs */
  --bl-bg-subtle: var(--bl-surface);     /* #F5F5F7 — bands, table heads, hover rows */
  --bl-bg-emphasis: var(--bl-sunken);    /* #E8E8ED — pressed and sunken fills */
  --bl-bg-inverted: var(--bl-navy);      /* the dark band and the call bar */

  /* Text, strongest first. `default` and `emphasis` are the same value today:
     our ink is already the darkest step we have, and there is no softer body
     ink to sit under it. The name exists so a heading can ask for "the
     strongest text" without asserting that it equals the body colour — it is
     the token that would move first if a softer body ink were ever
     introduced. `subtle` and `muted` are likewise one value today: Apple's
     lighter #86868B is 3.62 on white and fails AA, so meta text and secondary
     text share the one grey that passes. Both pairs are documented rather
     than collapsed, because collapsing them is the change that cannot be
     undone later without touching every screen. */
  --bl-text-emphasis: var(--bl-ink-900); /* 16.83 on default, 15.46 on subtle */
  --bl-text-default: var(--bl-ink-900);  /* 16.83 on default ground */
  --bl-text-subtle: var(--bl-text-2);    /* 5.07 on default, 4.66 on subtle */
  --bl-text-muted: var(--bl-muted);      /* 5.07 on default, 4.66 on subtle */
  --bl-text-inverted: var(--bl-white);   /* words on a coloured or dark fill */

  /* Lines, faintest first. None of these is a text colour.
     `emphasis` is 2.21 on white — enough for a card's hover border, which is
     decoration, and NOT enough for a line that is the only signal of a state
     (WCAG 1.4.11 wants 3:1 for that; see --bl-assumed-line below). */
  --bl-border-subtle: var(--bl-rule-soft);   /* inner rules inside a panel */
  --bl-border-default: var(--bl-blue-line);  /* the card border, 1.51 on ground */
  --bl-border-emphasis: var(--bl-border-hover); /* under the pointer, 2.21 on ground */
  --bl-border-inverted: var(--bl-navy-line);

  /* --- State. Four states, two shades, no more. -------------------------

     `-subtle` is a ground to put the state's own ink on; `-emphasis` is that
     ink, and the same value serves as the border. The pair is the contract:
     emphasis-on-subtle is a checked combination, and so is emphasis-on-ground.

     Which one to reach for:

       info      Something is true and worth reading. It is not a problem and
                 nothing is asked of the owner. Beta marks, "what this is"
                 notes, the current row. This is the accent, so it is also the
                 easiest one to overspend — see the note at the end.
       success   Something the owner wanted has actually happened, verified.
                 Not "normal": a usage bar at 12% of its allowance is not a
                 success, it is a Tuesday. If nothing has *happened*, this is
                 the wrong token.
       attention Something needs a person, or a fact is not as solid as it
                 looks, and nothing is broken yet. The stale-write pill
                 ("Connected · nothing written for 41 days"), an overdue next
                 step, a usage bar past its allowance, a paused agent.
       error     Something is broken or refused, now, and it is ours or the
                 provider's rather than a decision the owner has yet to make.
                 A failed write, a 500, a destructive confirm.

     The attention/error line is the one that gets crossed. Test: if the
     honest sentence is "we do not know" or "this may need you", it is
     attention. If it is "this did not work", it is error. `connectionPill`
     in src/lib/integrations/evidence.ts is the worked example — a probe that
     got no answer is attention, a connection we have been *told* is dead is
     error. */

  --bl-info-subtle: var(--bl-blue-tint);       /* #F0F6FE */
  --bl-info-emphasis: var(--bl-accent-text);   /* 5.12 on info-subtle, 5.57 on ground, 5.11 on bg-subtle */

  --bl-success-subtle: var(--bl-success-tint); /* #ECFDF5 */
  --bl-success-emphasis: var(--bl-success);    /* 5.21 on success-subtle, 5.48 on ground, 5.04 on bg-subtle */

  --bl-attention-subtle: var(--bl-warning-tint); /* #FFFBEB */
  --bl-attention-emphasis: var(--bl-warning);    /* 4.84 on attention-subtle, 5.02 on ground, 4.61 on bg-subtle */
  /* Long text on the attention wash. 4.84 clears AA but leaves nothing over;
     a sentence rather than a pill's two words gets the darker ink (6.84 on
     attention-subtle). Not a third shade of the state — the same ink, for a
     longer line. */
  --bl-attention-ink: var(--bl-warning-ink);

  --bl-error-subtle: var(--bl-danger-tint);    /* #FEF2F2 */
  --bl-error-emphasis: var(--bl-danger);       /* 5.91 on error-subtle, 6.47 on ground, 5.94 on bg-subtle */

  /* Words on a state used as a *fill* rather than as a wash: the blue button,
     a destructive confirm. White on every one of the four clears AA —
     info 4.70, success 5.48, attention 5.02, error 6.47. */
  --bl-on-state: var(--bl-white);

  /* --- Measured, or assumed ---------------------------------------------

     Audit F14: /sales/revenue is the best page in the repo at labelling, and
     then renders AED 8,616, 17 paying venues and AED 45,056 in tiles
     identical to the measured MRR tiles at the top of the same page, with the
     caveat below the twelve-month table. These are the numbers that get
     screenshotted into a deck.

     So a projected figure is drawn differently from a measured one, and that
     difference is a token rather than a decision taken once: no fill, a
     dashed outline, and the number one step back from measured ink.

     The outline is the only non-text signal that a tile is a projection, so
     it is held to the 3:1 that WCAG 1.4.11 asks of a meaningful graphic
     rather than to a hairline's 1.51 — hence the text grey (5.07 on ground)
     and not --bl-border-emphasis (2.21). It is deliberately heavier than a
     card border: that is the whole point of it. */
  --bl-assumed-ground: transparent;      /* not filled: an assumption is not a record */
  --bl-assumed-line: var(--bl-muted);    /* 5.07 on ground, 4.66 on bg-subtle */
  --bl-assumed-ink: var(--bl-text-2);    /* 5.07 on ground — measured money keeps the ink */

  /* --- Spending the accent ----------------------------------------------

     Cal.com is near-monochrome and breaks it in exactly one place: the
     unconfirmed-bookings badge, in their attention orange. Colour means
     something there because there is almost none of it.

     We are not going monochrome — the blue sells. But inside the dashboard
     the same economy applies, and it is a rule rather than a taste: a screen
     spends colour on what needs a person. A state token on a thing that is
     merely normal (a usage bar under its allowance, a routine item in a list
     where every item is already there because it needs attention) spends the
     reader's eye on nothing and leaves nothing for the row that is actually
     wrong. Where a surface has no state to report, it uses the prominence
     family above and stays grey. */
}


/* The site's own names, mapped onto the brand tokens. */
:root {
  /* Warmes Papier statt reinem Weiß. Reines Weiß ist auf einem Bildschirm eine
     Lichtquelle; Papier ist es nicht, und die ganze Haltung dieser Seite ist
     gedruckt, nicht beleuchtet. */
  --paper: var(--bl-ground);
  --paper-2: var(--bl-surface);
  --ink: var(--bl-ink-900);
  --ink-2: var(--bl-text-2);
  --ink-3: var(--bl-muted);

  /* The accent. The names still say brass because every rule below uses
     them; since the Ink + Indigo recolour they resolve to indigo in
     public/brand/tokens.9dcd0f0b.css, checked at 4.5:1 or better for small text. */
  --brass: var(--bl-accent-text);
  --brass-soft: var(--bl-blue-tint);
  --brass-fill: var(--bl-blue);

  /* Haarlinien. Eine 1px-Linie in Tinte bei 12% ist das, was gedruckte
     Sachen benutzen, statt Karten mit Schatten übereinanderzustapeln. */
  --rule: var(--bl-rule);
  --rule-soft: var(--bl-rule-soft);

  /* Die Auszeichnungsschrift, an einer Stelle.
     Vorher stand '"Instrument Serif", Georgia, serif' achtzehnmal im
     Stylesheet; ein Wechsel war eine Suche, bei der man eine übersieht. */
  --serif: var(--bl-font-display); /* IBM Plex Sans. The name is historical; it stays so every rule follows the token */

  /* Semantic roles, so a palette change is a token change, not a hunt.
     Each points at a brand token today; none carries a colour of its own
     except the shadows, which the tokens only offer in one size. */
  /* Apple blue with white words (4.70:1); hover goes a step darker (4.94:1). The
     bell on the button is the inverse mark: a white badge with a blue bell. */
  --btn-primary-bg: var(--bl-blue);
  --btn-primary-text: var(--bl-ground);
  --btn-primary-hover-bg: var(--bl-blue-hover);
  --btn-primary-hover-text: var(--bl-ground);
  --btn-primary-mark: url("/brand/belline-mark-inverse.e496e235.svg");
  --btn-primary-hover-mark: url("/brand/belline-mark-inverse.e496e235.svg");
  --mark-ground: var(--bl-blue);    /* the bell button's badge */
  --mark-glyph: var(--bl-ground);     /* the white bell inside it */
  --accent-line: var(--bl-blue-line); /* decorative rules and dots, never text */
  --surface-dark: var(--bl-ink-900);  /* the call card's header bar */
  --on-dark: var(--bl-ground);        /* text on --surface-dark */
  --on-dark-accent: var(--bl-blue-lit); /* labels and the level meter on --surface-dark (5.58:1) */
  --site-shadow-sheet: 0 18px 34px -22px rgba(0, 0, 0, 0.5);
  --site-shadow-fab: 0 14px 34px -14px rgba(0, 0, 0, 0.5);
  --site-shadow-fab-soft: 0 12px 28px -14px rgba(0, 0, 0, 0.42);
  --site-shadow-chat-dock: 0 24px 60px -20px rgba(17, 17, 17, 0.55);
  --site-shadow-call-dock: 0 20px 46px -16px rgba(17, 17, 17, 0.4);

  color-scheme: light;
}

* { box-sizing: border-box; }

/* The page never scrolls sideways. One badge too wide for a phone made every
   page 8–58px wider than the screen (launch audit, 15 Oct 2026); the badge is
   fixed (`.cal-head .state`), and this is the net under the next one. `clip`
   rather than `hidden`, because hidden makes the body a scroll container and
   the sticky header stops sticking. It hides an overflow, it does not mend it:
   tests/audit.spec.ts measures every phone page with this switched off. */
html,
body { overflow-x: clip; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--bl-font-text);
  /* 18px, nicht 17. Auf einem Laptop in Armlänge ist der Unterschied genau
     der zwischen "lesbar" und "angenehm"; die ganze Seite ist Fließtext mit
     einer Antiqua daneben, und die Antiqua wirkt nur groß, wenn die Grotesk
     daneben nicht schrumpft. */
  font-size: 18px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

.wrap { max-width: 1220px; margin: 0 auto; padding: 0 36px; }

/* --- Typografie ------------------------------------------------------------
   Fraunces für alles Große, Instrument Sans für alles Kleine.

   Vorher stand hier Instrument Serif. Sie ist schön und sie hat genau einen
   Schnitt, und der ist leicht — bei 76 px eine elegante Auszeichnungsschrift,
   bei 21 bis 26 px dünn und eng. Und dort stand sie zwölfmal:
   Zwischenüberschriften, Uhrzeiten, FAQ-Zeilen, Anrufernamen. Das war das,
   was sich falsch anfühlte.

   Fraunces hat eine Gewichtsachse und — wichtiger — eine optische Achse. Der
   Browser wählt sie automatisch nach Schriftgröße (font-optical-sizing), also
   wird der Strich kräftiger, sobald die Schrift kleiner wird, statt zu
   verschwinden. Eine Familie, zwei Aufgaben, ohne zweite Datei.

   Und ausdrücklich nicht Manrope, Inter oder Space Grotesk. Die drei sind
   inzwischen die Standardantwort, und eine Standardantwort sieht aus wie
   eine Standardantwort. */

.display {
  font-family: var(--serif);
  /* Direction C: Bricolage Grotesque 700, tight. The optical-size axis gives
     the big sizes their inky warmth on its own. */
  font-weight: 700;
  letter-spacing: var(--bl-track-h1);
  line-height: 1;
  text-wrap: balance;
  margin: 0;
}

h1.display { font-size: clamp(2.6rem, 1.5rem + 4.4vw, 5.4rem); letter-spacing: var(--bl-track-display); line-height: 0.96; }
h2.display { font-size: clamp(1.85rem, 1.25rem + 2.1vw, 2.9rem); font-weight: 650; letter-spacing: var(--bl-track-h2); line-height: 1.08; }

.eyebrow {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: var(--bl-track-label);
  text-transform: uppercase;
  color: var(--brass);
  margin: 0 0 22px;
}

p { margin: 0 0 18px; color: var(--ink-2); max-width: 62ch; }
.lead { font-size: 1.2rem; line-height: 1.5; color: var(--ink-2); }

a { color: inherit; }

/* Focus ring: Lagoon 2px (Direction C). Rules below that set their own win. */
:focus-visible { outline: var(--bl-focus); outline-offset: var(--bl-focus-offset); }

/* --- Kopfzeile -------------------------------------------------------------
   Eine Haarlinie statt einer Leiste mit Schatten. Nichts schwebt.

   The header used to be written twice: here, and again 2,270 lines below
   under a second banner called "Header", which is where the values actually
   in force came from. Reading this block told you nothing about what the page
   looked like. It is one block now, holding the values that won. */

.top {
  position: sticky;
  top: 0;
  z-index: 20;
  /* Apple's translucent bar: the light grey ground at 80%, over a saturated
     blur. Written as a mix of the token rather than rgba(245, 245, 247, .8),
     so it follows the palette like everything else. */
  background: color-mix(in srgb, var(--bl-surface) 80%, transparent);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--bl-rule-soft);
}
/* `.top .top-in` and not `.top-in`, deliberately. The element carries both
   `wrap` and `top-in`, and `.wrap` sets the `padding` shorthand — which resets
   padding-block to 0. The old header block only got its 16px because it
   happened to be written 2,000 lines *after* the last `.wrap` rule; moving it
   up here silently flattened the bar to 44px. One extra class makes the header
   win on specificity instead of on luck, wherever either block is written. */
.top .top-in {
  display: flex;
  align-items: center;
  gap: 36px;
  padding-block: 16px;
}

/* Die Wortmarke ist gesetzter Text, kein Bild. Sie erbt damit die Schrift der
   Seite, skaliert ohne zweite Datei und lässt sich in einer Zeile ändern. */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  text-decoration: none;
  color: var(--ink);
}
/* 34 statt 26. In einer 1220-px-Leiste war das Zeichen ein Detail; eine
   Marke, die man suchen muss, ist keine. */
/* Glocke in Messing, daneben die Wortmarke in Instrument Sans, fett und eng
   (15.09.2026) — statt der Fraunces-Antiqua. Die Glocke ist so hoch wie die
   Versalhöhe plus Unterlänge des Namens, damit beides als eine Zeile steht. */
/* Direction C: the bell button (brass badge, ink bell) and the name in
   Bricolage Grotesque 700. Header lockup 38px badge / 28px name, as on the
   approved canvas. */
.brand svg { width: 34px; height: 34px; display: block; flex: none; }
footer .brand svg { width: 32px; height: 32px; }
.brand span {
  /* The wordmark, not a heading: its own token, so the logo stays the same
     drawing as the SVG lockups when the display face changes. */
  font-family: var(--bl-font-wordmark);
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 1;
  color: var(--bl-ink-900);
}
footer .brand span { font-size: 1.55rem; }

.top nav { display: flex; align-items: center; gap: 30px; margin-inline-start: auto; }
.top nav a {
  text-decoration: none;
  font-size: 0.95rem;
  font-weight: 400;
  color: var(--bl-ink-900);
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
}
.top nav a:hover { color: var(--bl-accent-text); border-bottom-color: transparent; }

/* Die eine Handlung im Kopf sieht aus wie eine Handlung. Fünf gleich graue
   Wörter nebeneinander sind eine Liste, kein Angebot. */
.top nav .nav-cta {
  padding: 11px 22px;
  border-radius: 999px;
  background: var(--bl-blue);
  color: var(--bl-white);
  font-weight: var(--bl-weight-button);
  border-bottom: 0;
  box-shadow: none;
}
.top nav .nav-cta:hover { background: var(--bl-blue-hover); color: var(--bl-white); box-shadow: none; }
/* Sichtbar neben "Get Belline", wie gewünscht — aber als Textzeile, nicht als
   zweite Pille. Zwei gleich schwere Pillen nebeneinander sind zwei
   Hauptknöpfe, und die Seite hat genau einen. */
.top nav .nav-quiet {
  padding: 9px 4px;
  color: var(--bl-ink-900);
}
.top nav .nav-quiet:hover { color: var(--bl-ink-900); }

/* Der Aufklapper. Auf dem Laptop unsichtbar, auf dem Telefon das Einzige
   rechts. Ein Strich, der sich zum Kreuz dreht — kein Drei-Strich-Symbol,
   weil die Seite sonst nirgends mehrere parallele Linien benutzt. */
.menu-toggle {
  display: none;
  margin-inline-start: auto;
  width: 46px;
  height: 46px;
  padding: 0;
  border: 1px solid var(--card-line);
  border-radius: 999px;
  background: none;
  cursor: pointer;
  position: relative;
}
.menu-toggle .bar,
.menu-toggle .bar::before,
.menu-toggle .bar::after {
  position: absolute;
  left: 50%;
  width: 18px;
  height: 1.5px;
  background: var(--bl-ink-900);
  transform: translateX(-50%);
  transition: transform 0.2s ease, opacity 0.15s ease;
}
.menu-toggle .bar { top: 50%; margin-top: -0.75px; }
.menu-toggle .bar::before { content: ""; top: -6px; }
.menu-toggle .bar::after { content: ""; top: 6px; }
.menu-toggle[aria-expanded="true"] .bar { transform: translateX(-50%) rotate(45deg); }
.menu-toggle[aria-expanded="true"] .bar::before { transform: translateX(-50%) translateY(6px) rotate(-90deg); }
.menu-toggle[aria-expanded="true"] .bar::after { opacity: 0; }

/* --- Buttons ---------------------------------------------------------------
   Kein 8px-Radius auf allem. Die primäre Handlung ist eine gefüllte Pille,
   die sekundäre eine Linie — zwei Formen, nicht zwei Grautöne. */

/* Direction C: the primary is Bell Brass with ink words (5.62:1) and carries
   the bell button at its leading edge; the secondary is an ink outline. White
   never sits on brass (3.36:1). */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 28px;
  border-radius: 999px;
  border: 1px solid var(--btn-primary-bg);
  background: var(--btn-primary-bg);
  color: var(--btn-primary-text);
  font: inherit;
  font-size: 0.98rem;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
/* No bell mark inside the primary button any more (site review, 2026-09-17):
   the words are the call to action. */
.btn:hover { background: var(--btn-primary-hover-bg); border-color: var(--btn-primary-hover-bg); color: var(--btn-primary-hover-text); }
.btn.line { background: transparent; color: var(--ink); border-color: var(--ink); }
.btn.line:hover { background: var(--ink); color: var(--paper); }
.btn svg { width: 17px; height: 17px; }

/* --- Hero ------------------------------------------------------------------
   Links die Behauptung, rechts der Beleg. Das alte Layout war Text links,
   Screenshot rechts — die Anordnung, die jedes B2B-Produkt seit zehn Jahren
   benutzt. Der Beleg hier ist gesetzt, nicht fotografiert. */

.hero { padding: 84px 0 0; }
.hero .lead { margin-top: 28px; }
.cta-row { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 38px; }

.hero-note {
  margin-top: 26px;
  font-size: 0.88rem;
  color: var(--ink-3);
  max-width: 52ch;
}
.hero-note a { color: var(--ink-2); text-underline-offset: 3px; }

/* Die Zahlen als Zeile mit Haarlinien dazwischen, nicht als vier Karten.
   Karten sagen "vier getrennte Dinge"; das hier ist ein Satz. */
.facts {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
  margin-top: 96px;
  border-top: 1px solid var(--rule);
}
.fact { padding: 30px 28px 34px; border-inline-end: 1px solid var(--rule-soft); }
.fact:first-child { padding-inline-start: 0; }
.fact:last-child { border-inline-end: 0; }
.fact .n {
  font-family: var(--serif);
  font-weight: 700;
  font-size: 2.4rem;
  line-height: 1;
  letter-spacing: -0.02em;
}
.fact .k { font-size: 0.86rem; color: var(--ink-3); margin-top: 10px; }

/* --- Abschnitte ------------------------------------------------------------ */

section { padding: 110px 0; }
/* Die Kopfzeile klebt; ein Sprungziel landet sonst darunter. */
:target, #channels, #how, #for, #price, #faq, #book { scroll-margin-top: 92px; }
.rule { border-top: 1px solid var(--rule); }

/* Die Nummerierung ist echt: das sind drei Schritte in einer Reihenfolge.
   Ziffern auf Dinge zu setzen, die keine Reihenfolge haben, ist Dekoration,
   die so tut, als wäre sie Information. */
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 52px; margin-top: 64px; }
.step .num {
  font-family: var(--serif);
  font-size: 1.5rem;
  color: var(--brass);
  border-bottom: 1px solid var(--rule);
  padding-bottom: 14px;
  margin-bottom: 18px;
}
.step h3 { font-size: 1.08rem; font-weight: 600; margin: 0 0 10px; letter-spacing: -0.01em; }
.step p { font-size: 0.95rem; margin: 0; }

/* Frage und Antwort als Satzpaare mit einer Linie dazwischen. Der Inhalt ist
   ein Dialog; ein Raster aus Kacheln würde ihn zerlegen. */
.handled { margin-top: 56px; border-top: 1px solid var(--rule); }
/* Die Antwort gehört neben die Frage, nicht an den anderen Rand des
   Bildschirms. Bei 1220 px Breite standen zwischen "Do you have anything
   Friday?" und "Books it" gut 700 px Nichts, und das Auge muss die beiden
   Hälften erst wieder zusammensetzen. Die Zeile hört jetzt dort auf, wo ein
   Satz aufhört. */
.handled { max-width: 920px; }
.handled-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 40px;
  align-items: baseline;
  padding: 22px 0;
  border-bottom: 1px solid var(--rule-soft);
}
.handled-row .q {
  font-family: var(--serif);
  font-size: 1.42rem;
  letter-spacing: -0.015em;
  line-height: 1.25;
}
.handled-row .a { font-size: 0.9rem; color: var(--ink-3); text-align: end; white-space: nowrap; }
.handled-row .a.human { color: var(--brass); }

/* --- Fotografie ------------------------------------------------------------
   Randlos und groß. Ein Bild in einer Karte mit Rahmen und Schatten ist ein
   Bild, dem man nicht zutraut, allein zu stehen. */
.plate { margin-top: 72px; }
/* A trade page's "Belle at work" Reel: 9:16, so it is held to a phone's width
   beside the copy rather than stretched to the column. */
.reel { margin: 0; justify-self: center; width: 100%; max-width: 340px; }
.reel video { width: 100%; height: auto; aspect-ratio: 9 / 16; display: block; border-radius: var(--bl-radius-card); background: var(--bl-navy); }
.reel figcaption { margin-top: 12px; font-size: 0.9rem; color: var(--ink-2); }
.plate img { width: 100%; height: auto; display: block; }
.plate figcaption {
  margin-top: 14px;
  font-size: 0.84rem;
  color: var(--ink-3);
  padding-inline-start: 2px;
  border-inline-start: 2px solid var(--brass);
  padding-inline-start: 12px;
}

@media (max-width: 900px) {
  .wrap { padding: 0 22px; }
  body { font-size: 16px; }
  /* 82px: the bar above is 62px, so this is the first value that shows as a
     gap at all rather than hiding behind the header. See the note there. */
  .hero { padding-top: 82px; }
  .facts { grid-template-columns: repeat(2, 1fr); margin-top: 64px; }
  .fact { padding: 24px 20px 26px; }
  .fact:nth-child(2) { border-inline-end: 0; }
  .fact:nth-child(3) { padding-inline-start: 0; }
  .steps { grid-template-columns: 1fr; gap: 38px; }
  .handled-row { grid-template-columns: 1fr; gap: 6px; }
  .handled-row .a { text-align: start; }
  section { padding: 72px 0; }

  /* --- Das Menü auf dem Telefon -------------------------------------------
     Ein Blatt, das unter der Kopfzeile herunterkommt, nicht ein
     Vollbild-Overlay: die Seite bleibt sichtbar, also weiß man, wo man ist.
     Die Einträge stehen in der Antiqua und in Daumengröße — ein Menü, das
     man auf einem Telefon bedient, ist kein 13-px-Text. */
  .menu-toggle { display: block; }
  /* Written down rather than inherited, and written with two classes on
     purpose: `.top-in` also carries `wrap`, and the `.wrap` rule in the other
     max-width: 900px block further down sets the `padding` shorthand — which
     resets `padding-block` to 0. `.top .top-in` outranks it wherever it sits
     in the file, which is why the fix can live here, in the one place that
     defines the bar, instead of being restated below `.wrap` to win on order.
     Until it was, the bar was 47px tall around a 46px menu button: the
     bordered circle sat flush against the viewport edge and the hairline.
     12px (the desktop bar uses 16px) clears the circle on both sides and
     keeps the sticky bar at 71px — taller than Apple's 48px mobile nav,
     because this design's tap target is a 46px circle rather than a 17px
     glyph. The 24px the hero used to carry above itself comes off at 760px to
     pay for it; see the note there. */
  /* 8px, not 12. The bar was 71px around a 46px menu circle, and the hero's
     own 60px of top padding is *less* than that — so the sticky header covered
     all of it and the headline began at exactly zero pixels of air. Measured on
     belline.ai, 5 Oct 2026: header bottom 71, headline top 71.

     Nine pixels off the bar and twenty-two onto the hero below buys twenty
     pixels of visible air for eleven pixels of the first screen — the cheapest
     version of "push Someone always answers. a bit down" (founder). The circle
     still clears the hairline and the viewport edge by 8px on each side. */
  .top .top-in { gap: 16px; padding-block: 5px; }

  .top nav {
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    display: grid;
    gap: 0;
    margin: 0;
    padding: 4px 22px calc(22px + env(safe-area-inset-bottom, 0px));
    background: var(--bl-ground);
    border-bottom: 1px solid var(--rule);
    box-shadow: var(--site-shadow-sheet);

    /* Zu, und zwar so, dass es für Tastatur und Vorleseprogramm auch zu ist:
       visibility, nicht nur opacity. Ein unsichtbarer Link, den man antabben
       kann, ist eine Falle. */
    visibility: hidden;
    opacity: 0;
    transform: translateY(-8px);
    transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s;
  }
  .top nav[data-open="true"] {
    visibility: visible;
    opacity: 1;
    transform: none;
  }
  /* Taller than a phone on its side (three links, the country and language,
     "Sign in" and "Get started" are about 560px): the menu scrolls inside
     itself, so its last button can be reached rather than hanging below the
     screen. 64px is the bar above it, with its 44px button and 5px either side
     and a little over. */
  .top nav {
    max-height: calc(100vh - 64px);
    max-height: calc(100dvh - 64px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  .top nav a {
    font-family: var(--bl-font-display);
    font-size: 1.3rem;
    font-weight: var(--bl-weight-display);
    letter-spacing: -0.015em;
    color: var(--bl-ink-900);
    padding: 17px 0;
    border-bottom: 1px solid var(--rule-soft);
  }
  .top nav a:last-child { border-bottom: 0; }
  .top nav .nav-cta {
    font-family: var(--bl-font-text);
    font-size: 1rem;
    font-weight: var(--bl-weight-button);
    color: var(--bl-white);
    text-align: center;
    padding: 16px 24px;
    margin-top: 18px;
    border-bottom: 0;
  }
  /* Im aufgeklappten Menü wieder eine Zeile, keine Pille: dort stehen die
     Punkte untereinander, und eine Pille zwischen lauter Textzeilen sieht aus,
     als wäre sie versehentlich dort gelandet. */
  .top nav .nav-quiet {
    display: block;
    font-family: var(--bl-font-text);
    font-size: 0.95rem;
    font-weight: 400;
    padding: 16px 0 0;
    border-bottom: 0;
    box-shadow: none;
    border-radius: 0;
  }
}

/* --- Auftritt -------------------------------------------------------------
   Der Hero setzt sich einmal zusammen, gestaffelt von oben nach unten.

   Wichtig: der Ruhezustand ist der sichtbare. Die Animation läuft *von* einer
   Verschiebung *zu* dem, was ohnehin dasteht — nicht von opacity:0 aus, das
   auf etwas wartet. Ohne CSS-Animation, ohne JavaScript, in einem Thumbnail
   oder in einem Screenshot ist die Seite vollständig da. Eine Seite, die erst
   durch Bewegung lesbar wird, ist kaputt, nicht lebendig. */

/* Nur Bewegung, keine Deckkraft.
 *
 * Die erste Fassung blendete von opacity: 0 auf — und genau das hatte der
 * Kommentar oben als Fehler bezeichnet, während die Keyframes es taten. Die
 * Prüfung hat es gefunden: axe misst die Seite so, wie sie in dem Moment
 * aussieht, und fand Messing bei 4.35 statt 4.92 und das Grau bei 4.31 statt
 * 4.91 — nicht weil die Farben falsch sind, sondern weil der Text noch bei
 * 78% Deckkraft stand. Ein Mensch, der in dieser halben Sekunde liest, hat
 * dasselbe Problem.
 *
 * Verschoben statt eingeblendet ist die Bewegung dieselbe und der Text von der
 * ersten Zeile an vollständig lesbar. */
@keyframes rise {
  from { transform: translateY(14px); }
  to   { transform: none; }
}

.rise { animation: rise 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) both; }
.rise-1 { animation-delay: 0.06s; }
.rise-2 { animation-delay: 0.14s; }
.rise-3 { animation-delay: 0.22s; }
.rise-4 { animation-delay: 0.30s; }

/* --- Hero: zweispaltig ----------------------------------------------------- */

.hero-in {
  display: grid;
  grid-template-columns: minmax(0, 1.02fr) minmax(0, 0.98fr);
  gap: 64px;
  align-items: start;
}
/* 13ch, nicht 11: bei 11 brach "Someone always answers." dreizeilig, und
   drei Zeilen aus je einem Wort lesen als Gedicht, nicht als Aussage. */
.hero h1 { max-width: 15ch; }
.hero .lead { max-width: 42ch; }

/* --- Das gesetzte Gespräch -------------------------------------------------
   Der Beleg im Hero. Ein Interview in einer Zeitschrift, kein Chatfenster:
   Haarlinien statt Sprechblasen, der Anrufer in der Antiqua, Belline in der
   Grotesk. Zwei Stimmen, zwei Schriften — dieselbe Unterscheidung, die ein
   gedrucktes Interview trifft, und sie funktioniert ohne eine einzige Farbe. */

.script {
  margin: 8px 0 0;
  padding: 0;
  border-top: 1px solid var(--ink);
}
.script-head {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding: 14px 0 22px;
  font-size: 0.8rem;
  color: var(--ink-3);
}
.script-head .at {
  font-family: var(--serif);
  font-size: 1.15rem;
  color: var(--brass);
  letter-spacing: -0.01em;
}

.script .line { padding: 0 0 22px; }
.script .who {
  display: block;
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 7px;
}
.script .line p { margin: 0; max-width: none; }

.script .caller p {
  font-family: var(--serif);
  font-size: 1.42rem;
  line-height: 1.24;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.script .agent {
  padding-inline-start: 26px;
  border-inline-start: 1px solid var(--rule);
}
.script .agent p { font-size: 0.98rem; color: var(--ink-2); }

.script-out {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding-top: 18px;
  border-top: 1px solid var(--rule);
  font-size: 0.86rem;
  color: var(--ink-2);
}
.script-out .tag {
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brass);
  border: 1px solid var(--brass-soft);
  border-radius: 999px;
  padding: 5px 11px;
}

/* --- Beiseite gesprochen --------------------------------------------------- */

.aside {
  margin-top: 64px;
  padding-inline-start: 26px;
  border-inline-start: 2px solid var(--brass);
  max-width: 60ch;
}
.aside h3 {
  font-family: var(--serif);
  font-weight: 400;
  font-size: 1.5rem;
  margin: 0 0 10px;
  letter-spacing: -0.015em;
}
.aside p { margin: 0; font-size: 0.95rem; }

/* --- Fotografie ------------------------------------------------------------ */

.plates {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 34px;
  margin-top: 56px;
}
.plate { margin: 0; }
.plate img { width: 100%; height: auto; display: block; }
.plate figcaption { margin-top: 16px; font-size: 0.9rem; color: var(--ink-2); }
.plate figcaption strong {
  display: block;
  font-family: var(--serif);
  font-weight: 400;
  font-size: 1.28rem;
  color: var(--ink);
  letter-spacing: -0.015em;
  margin-bottom: 7px;
}

.trade-links { display: flex; flex-wrap: wrap; gap: 26px; margin-top: 40px; }
.trade-links a {
  font-size: 0.92rem;
  color: var(--ink-2);
  text-decoration: none;
  border-bottom: 1px solid var(--brass-soft);
  padding-bottom: 3px;
}
.trade-links a:hover { border-bottom-color: var(--brass); color: var(--ink); }

/* --- Preise ----------------------------------------------------------------
   Spalten mit Haarlinien dazwischen, keine schwebenden Karten. Der empfohlene
   Plan wird durch eine Tintenlinie oben und mehr Luft ausgezeichnet, nicht
   durch einen Schatten — Schatten sind auf Papier eine Lüge. */

.cycle {
  display: inline-flex;
  gap: 4px;
  margin-top: 36px;
  padding: 4px;
  border: 1px solid var(--rule);
  border-radius: 999px;
}
.cycle-opt {
  appearance: none;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: 0.9rem;
  color: var(--ink-2);
  padding: 9px 20px;
  border-radius: 999px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 9px;
}
.cycle-opt.is-on { background: var(--ink); color: var(--paper); }
.cycle-save {
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--brass);
}
.cycle-opt.is-on .cycle-save { color: var(--brass-soft); }

/* Die drei Spalten teilen sich ein Raster, statt jede für sich zu rechnen.
   Ohne das standen die drei Preise auf drei verschiedenen Höhen — weil der
   Hinweis "Most popular" und die unterschiedlich langen Untertitel jede
   Spalte anders weit nach unten schoben. Bei einer Preistabelle sieht man
   das sofort, auch wenn man nicht sagen kann, was stört. */
.plans {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  /* tag, name, who it suits, price, allowances, what differs, button */
  grid-template-rows: auto auto auto auto auto 1fr auto;
  gap: 0;
  margin-top: 46px;
  border-top: 1px solid var(--rule);
}
.plan { grid-row: span 7; }
@supports (grid-template-rows: subgrid) {
  .plan { display: grid; grid-template-rows: subgrid; }
}
.plan {
  padding: 34px 32px 38px;
  border-inline-end: 1px solid var(--rule-soft);
  display: flex;
  flex-direction: column;
}
.plan:first-child { padding-inline-start: 0; }
.plan:last-child { border-inline-end: 0; padding-inline-end: 0; }
/* Innenlinie statt Rahmen: ein border-top haette die Spalte um seine eigene
   Breite nach unten geschoben, und das mit -1px zurueckzuziehen liess den
   mittleren Preis genau ein Pixel hoeher stehen als die beiden daneben. */
.plan.is-best { box-shadow: inset 0 2px 0 var(--ink); }
.plan-tag {
  /* Auch leer, als Platzhalter in den beiden anderen Spalten — und zwar
     genau eine Zeilenhoehe hoch (font-size mal line-height), sonst sitzt der
     Preis daneben sechs Pixel hoeher als der in der Mitte. */
  min-height: 1.55em;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: var(--bl-track-label);
  text-transform: uppercase;
  color: var(--brass);
  margin-bottom: 14px;
}
.plan h3 {
  font-family: var(--serif);
  font-weight: 400;
  font-size: 1.6rem;
  margin: 0;
  letter-spacing: -0.015em;
}
.plan-sub { font-size: 0.88rem; color: var(--ink-3); margin: 8px 0 0; max-width: 30ch; }

.plan-price { margin: 26px 0 24px; }
.plan-price .amt {
  display: block;
  font-family: var(--serif);
  font-weight: 700;
  font-size: 2.9rem;
  line-height: 1;
  letter-spacing: -0.025em;
}
.plan-price .per { display: block; font-size: 0.86rem; color: var(--ink-3); margin-top: 7px; }
.plan-price .billed { display: block; font-size: 0.78rem; color: var(--ink-3); margin-top: 10px; }

.plan ul { list-style: none; margin: 0 0 28px; padding: 0; display: grid; gap: 11px; }
.plan li {
  font-size: 0.9rem;
  line-height: 1.45;
  color: var(--ink-2);
  padding-inline-start: 18px;
  position: relative;
}
.plan li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 0.62em;
  width: 6px;
  height: 1px;
  background: var(--brass);
}
.plan .btn { margin-top: auto; align-self: start; }

/* Die Module unter den drei Paketen: dieselben Haarlinien, kleiner gesetzt.
   Ein Kanal pro Spalte, damit man "nur den Chat" findet, ohne die Pakete
   noch einmal lesen zu muessen. */
.market[hidden] { display: none; }
.market-pick {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 36px 16px 0 0;
  font-size: 0.9rem;
  color: var(--ink-2);
}
.market-pick select {
  font: inherit;
  padding: 8px 12px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: transparent;
  color: var(--ink);
}
.modules { margin-top: 56px; padding-top: 34px; border-top: 1px solid var(--rule); }
.modules-head {
  font-family: var(--serif);
  font-weight: 400;
  font-size: 1.4rem;
  letter-spacing: -0.015em;
  margin: 0 0 22px;
}
.module-groups {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0 32px;
}
.module-group { list-style: none; margin: 0; padding: 0; }
.module { padding: 16px 0 18px; border-top: 1px solid var(--rule-soft); }
.module-row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.module-name { font-size: 0.95rem; font-weight: 600; color: var(--ink); }
.module-price { font-family: var(--serif); font-size: 1.15rem; white-space: nowrap; color: var(--ink); }
.module-what { font-size: 0.86rem; color: var(--ink-2); margin: 6px 0 0; }
.module details { margin-top: 8px; font-size: 0.82rem; color: var(--ink-3); }
.module summary { cursor: pointer; color: var(--ink-2); }
.module details ul { margin: 8px 0 0; padding-inline-start: 16px; display: grid; gap: 5px; }
.module-cta {
  display: inline-block;
  margin-top: 10px;
  font-size: 0.84rem;
  color: var(--ink);
  text-underline-offset: 3px;
}
.module-cta:hover { color: var(--brass); }

.compare {
  margin: 52px 0 0;
  max-width: none;
  text-align: center;
  font-family: var(--serif);
  font-size: 1.6rem;
  letter-spacing: -0.015em;
  color: var(--ink);
}

.terms.terms-4 { grid-template-columns: repeat(4, 1fr); }
.terms {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 34px;
  margin-top: 56px;
  padding-top: 34px;
  border-top: 1px solid var(--rule);
}
.terms h4 { margin: 0 0 9px; font-size: 0.82rem; font-weight: 600; }
.terms p { margin: 0; font-size: 0.84rem; line-height: 1.55; color: var(--ink-3); }

/* --- Fragen ---------------------------------------------------------------- */

.faq { margin-top: 48px; border-top: 1px solid var(--rule); }
.faq details { border-bottom: 1px solid var(--rule-soft); }
.faq summary {
  list-style: none;
  cursor: pointer;
  padding: 24px 0;
  font-family: var(--serif);
  font-size: 1.3rem;
  letter-spacing: -0.015em;
  display: flex;
  justify-content: space-between;
  gap: 20px;
  align-items: baseline;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; color: var(--brass); font-size: 1.2rem; }
.faq details[open] summary::after { content: "–"; }
.faq .answer { padding-bottom: 24px; }
.faq .answer p { margin: 0 0 12px; font-size: 0.95rem; max-width: 66ch; }
.faq .answer p:last-child { margin-bottom: 0; }

/* --- Schluss und Formular --------------------------------------------------- */

.closer { background: var(--paper-2); }
.book-grid {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: 56px;
  align-items: start;
}
.fine { font-size: 0.86rem; color: var(--ink-3); margin-top: 22px; }

.book-form { display: grid; gap: 18px; }
.f-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
.f { display: grid; gap: 7px; min-width: 0; }
.f > span { font-size: 0.78rem; font-weight: 500; color: var(--ink-2); letter-spacing: 0.02em; }
.f .opt { font-weight: 400; color: var(--ink-3); }

/* Unterstrichene Felder statt Kästen. Ein Formular auf Papier ist eine Linie,
   auf die man schreibt. */
.book-form input,
.book-form select,
.book-form textarea {
  font: inherit;
  font-size: 0.98rem;
  width: 100%;
  padding: 11px 2px;
  border: 0;
  border-bottom: 1px solid var(--rule);
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  transition: border-color 0.15s ease;
}
.book-form textarea { resize: vertical; min-height: 78px; }
.book-form input:focus,
.book-form select:focus,
.book-form textarea:focus { outline: none; border-bottom-color: var(--ink); }
.book-form input.is-bad, .book-form select.is-bad { border-bottom-color: var(--bl-danger); }
.book-form input.is-hint { border-bottom-color: var(--brass); }

.f-err { font-size: 0.8rem; font-style: normal; color: var(--bl-danger); }
.f-err.is-hint { color: var(--brass); }
.f-err button {
  appearance: none; border: 0; background: none; font: inherit; font-size: inherit;
  color: var(--ink); text-decoration: underline; cursor: pointer; padding: 0;
}
.book-submit { justify-content: center; margin-top: 6px; }
.f-note { font-size: 0.82rem; color: var(--ink-3); margin: 0; }
.f-note.is-good { color: var(--bl-success); }
.f-note.is-bad { color: var(--bl-danger); }

/* --- Was die verpassten Anrufe wert sind ----------------------------------- */
.roi { max-width: 760px; margin-top: 34px; }
.roi input[type="number"] { font-variant-numeric: tabular-nums; }
.roi-out {
  font-family: var(--serif);
  font-size: clamp(1.4rem, 2.6vw, 1.9rem);
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--ink);
  max-width: 34ch;
  margin: 34px 0 12px;
}
.roi-fine { font-size: 0.86rem; color: var(--ink-3); max-width: 60ch; margin: 0; }

/* --- Rechtliches ------------------------------------------------------------ */
.legal { max-width: 760px; padding-top: 72px; padding-bottom: 96px; }
.legal .display { font-size: clamp(2.2rem, 5vw, 3.4rem); margin: 10px 0 8px; }
.legal-updated { font-size: 0.86rem; color: var(--ink-3); margin: 0 0 36px; }
.legal h2 { font-family: var(--serif); font-weight: 400; font-size: 1.5rem; margin: 44px 0 12px; }
.legal h3 { font-size: 1rem; font-weight: 600; margin: 24px 0 8px; }
.legal p, .legal li { color: var(--ink-2); line-height: 1.65; }
.legal ul { padding-inline-start: 20px; }
.legal li { margin-bottom: 8px; }
.legal a { color: var(--ink); text-underline-offset: 3px; }

/* --- /docs/embed -----------------------------------------------------------
   The only page on this site whose reader is mid-task with an editor open, so
   it is the only one with code on it. A snippet somebody has to reflow by hand
   before pasting is a snippet they will retype and get wrong, so the block
   wraps rather than running off the side. */
.legal pre {
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 10px;
  padding: 14px 16px;
  margin: 14px 0 20px;
}
.legal pre code {
  font: 400 0.82rem/1.6 ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  color: var(--ink);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.legal p > code, .legal li > code, .legal td > code, .legal th > code {
  font: 400 0.86em/1.4 ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  background: var(--paper);
  border-radius: 4px;
  padding: 1px 5px;
  overflow-wrap: anywhere;
}
/* The attribute table has five columns and one of them is a paragraph. On a
   phone it scrolls inside its own box rather than dragging the whole page
   sideways: a body that scrolls horizontally loses people their place. */
.legal .table-wrap { overflow-x: auto; margin: 14px 0 20px; }
.legal table { border-collapse: collapse; width: 100%; min-width: 560px; }
.legal th, .legal td {
  text-align: start;
  vertical-align: top;
  padding: 9px 12px 9px 0;
  border-bottom: 1px solid var(--rule);
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--ink-2);
}
.legal th { color: var(--ink); font-weight: 600; white-space: nowrap; }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* --- Fuß ------------------------------------------------------------------- */

footer { border-top: 1px solid var(--rule); padding: 44px 0 60px; }
/* The text sits beside the brand, not against the right edge: the floating
   buttons live bottom right, and at the end of the page they covered the
   footer's last words and the sign-in link. On narrower screens the buttons
   cover the full width, so the footer leaves room below instead. */
.foot-in { display: flex; gap: 28px 96px; flex-wrap: wrap; align-items: flex-start; justify-content: flex-start; }
/* The line-height here is a target size, not a taste. The footer is six links
   in one paragraph, so where they wrap the vertical distance between two of
   them is exactly one line box. At 0.86rem that was 1.7 x 13.76px = 23.4px,
   and WCAG 2.2 AA "Target Size (Minimum)" asks for 24. It went unseen on
   Windows, where the metrics round the other way; Linux CI caught it on /try
   the first time the audit suite ran there. 1.9 clears the threshold by two
   pixels rather than by a rounding error. */
footer p { font-size: 0.86rem; color: var(--ink-3); margin: 0; line-height: 1.9; max-width: 62ch; }
/* The letterhead: who is selling this, in law. Quieter and tighter than the
   links above it — it is there to be checked, not read. Hidden entirely while
   there is no company, so the page never shows an empty line. */
.foot-legal { font-size: 0.78rem; line-height: 1.6; margin-top: 14px; max-width: 72ch; color: var(--ink-3); }
.foot-legal:has(> span:empty) { display: none; }
/* The German pages' Impressum (scripts/site-locale.ts): the footer's legal line, spelled out. */
.impressum { margin-top: 14px; max-width: 72ch; font-size: 0.78rem; line-height: 1.6; color: var(--ink-3); }
.impressum p { margin: 0 0 6px; }
.impressum-h { scroll-margin-top: 90px; }
.impressum a { color: inherit; }
@media (max-width: 1100px) { footer { padding-bottom: 220px; } }
footer a { color: var(--ink-2); text-underline-offset: 3px; }

/* --- The floating buttons ---------------------------------------------------
 *
 * Three buttons in the bottom right corner, and everything about them in one
 * place: what they look like, where they sit, how they ring, what they become
 * on a phone, and every state in which they stand down. Nothing below this
 * section may set their colour, their position or their animation.
 *
 * That rule is the fix for a real bug, not a tidiness preference. These
 * buttons used to be built here and repainted 2,200 lines further down, in a
 * second block also called "Floating buttons" — and the later block painted
 * the WhatsApp pill paper-white with a blue glyph, silently undoing the green
 * set here, because the last declaration wins. Nobody had changed the WhatsApp
 * rule; somebody had changed a rule that happened to sit underneath it.
 * `npm run check:tokens` now stops the colour half of that class of accident;
 * keeping each button whole and in one place stops the rest.
 *
 * They are on screen from the first paint. They used to wait for the hero to
 * scroll past, which hid every way of reaching Belline at the one moment every
 * visitor is looking; the hero leaves room for them instead ("Platz für die
 * Knöpfe", below).
 *
 * The bell is the lowest and the loudest: voice is what this product can do
 * and a chat widget cannot, so it stays the main button. The chat button above
 * it is deliberately the quieter of the two — paper with a contour — for the
 * visitor who cannot speak right now. WhatsApp sits above that in WhatsApp's
 * own green, because the mark is recognised before the words beside it are
 * read.
 */

/* The order, top to bottom, since 10 Oct 2026: phone, chat, WhatsApp,
   Instagram, and the bell at the foot — the founder's order for the set on
   every page, the same order Belle's row reads left to right with her face at
   the end of it (site.js `actions()`). The bell stands where she would. The
   markup comes from src/lib/site-contact.ts, in the same order. */
/* Round, icon-only, at every width (founder, 15 Oct 2026: "no text badges",
   on the desktop too). They were pills with their names written beside the
   icon above 900px and circles below it; now they are the circles everywhere,
   in one row along the bottom edge, read left to right in the founder's order
   with Belle's face at the end — exactly the row her video bubble draws
   (public/embed-video.js `.bvb-row`), so the corner looks the same whether her
   video came or not. Each button keeps its name three ways: `aria-label`,
   the `title` tooltip on hover, and its `-say` span, visually hidden.

   The row is one box (`.fabs`, from src/lib/site-contact.ts), so a button
   that is not drawn closes its gap. The box itself takes no clicks: only its
   buttons do, so the strip of page between them stays usable. */
.fabs {
  /* Number for number the row Belle lands in the corner with (embed-video.js
     `.bvb.is-mini`): 58px icons beside a 96px face, 56px and 96px on a phone.
     A smaller face was tried and refused once already ("the 60 px Belle"). */
  --fab: 58px;
  --fab-face: 96px;
  position: fixed;
  right: 20px;
  bottom: calc(20px + env(safe-area-inset-bottom, 0px));
  z-index: 40;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 10px;
  pointer-events: none;
}
/* Everything the five share: the same size, the same 4px halo of page colour
   and the same shadow. Only the colour and the delay in the ring differ below. */
.bell-fab,
.chat-fab,
.wa-fab,
.ig-fab,
.dial-fab {
  position: relative;
  flex: none;
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--fab);
  height: var(--fab);
  padding: 0;
  gap: 0;
  margin: 0;
  border-radius: 999px;
  font: inherit;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  box-shadow: 0 0 0 4px var(--bl-ground), var(--site-shadow-fab-soft);
  /* Their own stacking context, so the ring can sit at z-index: -1 without
     dropping behind the page itself. */
  isolation: isolate;
  transition: transform 0.16s ease;
}
/* The names, for screen readers only. The tooltip (`title`) shows them on hover. */
.bell-fab-say,
.chat-fab-say,
.dial-fab-say,
.ig-fab-say,
.wa-fab-say {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
/* A keyboard user sees where they are: Belline blue, outside the halo. */
.bell-fab:focus-visible,
.chat-fab:focus-visible,
.wa-fab:focus-visible,
.ig-fab:focus-visible,
.dial-fab:focus-visible {
  outline: 3px solid var(--bl-blue);
  outline-offset: 5px;
}
.bell-fab[hidden],
.chat-fab[hidden],
.wa-fab[hidden],
.ig-fab[hidden],
.dial-fab[hidden] { display: none !important; }

/* Der Ring. Liegt hinter dem Knopf (z-index: -1 im eigenen Stapelkontext),
   damit er nicht über der Schrift landet, und ist pointer-events: none, damit
   er den Klick nicht abfängt. Transparent hier: die Farbe setzt jeder Knopf
   für sich, unten. */
.bell-fab::after,
.chat-fab::after,
.wa-fab::after,
.dial-fab::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 2px solid transparent;
  pointer-events: none;
  opacity: 0;
  z-index: -1;
}

/* Ein Telefon, das klingelt.
 *
 * Drei Dinge auf demselben Takt, weil eins allein zu wenig war: das Zeichen
 * schwingt, der Knopf ruckt mit, und ein Ring läuft nach außen weg. Der Ring
 * ist der Teil, den man aus dem Augenwinkel sieht — eine 27-px-Glocke, die
 * sich dreht, sieht nur, wer ohnehin schon hinschaut.
 *
 * Der Takt ist 1,5 s und der Ausschlag 22°. Die Schwingung selbst bleibt
 * schnell und klingt ab: eine Glocke schwingt und steht dann still.
 *
 * Drei Knöpfe im Gleichtakt wären ein Alarm, drei nacheinander sind ein
 * Tresen, an dem etwas los ist — daher die versetzten Verzögerungen. Und es
 * hört nach dreimal auf: ein Knopf, der ewig wackelt, ist eine Werbetafel. */
.bell-fab,
.chat-fab,
.wa-fab { animation: bell-nudge 1.5s ease-in-out 3; }
.bell-fab svg,
.chat-fab svg,
.wa-fab svg { animation: bell-shake 1.5s ease-in-out 3; }
.bell-fab::after,
.chat-fab::after,
.wa-fab::after { animation: bell-ring 1.5s ease-out 3; }

@keyframes bell-shake {
  0%, 27%, 100% { transform: rotate(0deg); }
  2% { transform: rotate(-22deg); }
  4% { transform: rotate(22deg); }
  6% { transform: rotate(-19deg); }
  8% { transform: rotate(19deg); }
  10% { transform: rotate(-15deg); }
  12% { transform: rotate(15deg); }
  14% { transform: rotate(-11deg); }
  16% { transform: rotate(11deg); }
  18% { transform: rotate(-8deg); }
  20% { transform: rotate(8deg); }
  22% { transform: rotate(-4deg); }
  24% { transform: rotate(4deg); }
}
@keyframes bell-nudge {
  0%, 14%, 100% { transform: translateY(0) rotate(0deg); }
  3% { transform: translateY(-2px) rotate(-1.6deg); }
  7% { transform: translateY(-2px) rotate(1.6deg); }
  11% { transform: translateY(-1px) rotate(-0.8deg); }
}
@keyframes bell-ring {
  0%   { transform: scale(1); opacity: 0.55; }
  55%  { transform: scale(1.28); opacity: 0; }
  100% { transform: scale(1.28); opacity: 0; }
}

/* Der Telefonknopf. Dieselbe Form wie .wa-fab, eine Stufe darüber.
   "Can we use this number now on our site for demonstration… please make the
   button look like a phone. This makes me think if we should also offer the
   option of a hovering phone button, especially for mobile version" (Gründer,
   5. Okt. 2026) — und auf einem Telefon ist Antippen und Hören der kürzeste Weg
   zu einem Beweis, kürzer als jedes Chatfenster.
   Gedämpft, nicht laut: die Glocke ist die Hauptaktion, dies ist eine zweite
   Art hineinzukommen. Darum Tinte auf Papier mit einer Linie, nicht Blau. */
/* Dasselbe Maß wie der WhatsApp-Knopf darunter, in Navy mit Weiß.

   Die erste Fassung war Tinte auf Papier mit einer Linie — leiser, weil die
   Glocke die Hauptaktion ist. Der Gründer wollte das Gegenteil: "put it next to
   the others, same size, same shape, and the dark blue or black color we have
   on the landing page with white phone icon and white surrounding like the
   other buttons. make it ring like the others" (5. Okt. 2026). Er hat recht:
   drei Knöpfe in einer Reihe, von denen einer gedämpft ist, sehen nach einem
   Fehler aus und nicht nach einer Rangfolge.

   Navy ist der dunkle Bandgrund der Seite (--bl-navy). Weiß darauf liegt bei
   16.83:1. Der weiße Ring ist derselbe 4px-Rahmen, den Glocke und WhatsApp
   tragen.

   Der Hexwert steht hier bewusst nicht: check:tokens liest die ganze Datei,
   Kommentare eingeschlossen, und das ist richtig so — eine Farbe, die als Text
   danebensteht, veraltet still, sobald das Token sich ändert. */
.dial-fab {
  background: var(--bl-navy);
  color: var(--bl-white);
  border: 1px solid var(--bl-navy);
}
.dial-fab svg { width: 23px; height: 23px; display: block; fill: var(--bl-white); }
.dial-fab[hidden] { display: none !important; }
.dial-fab::after { border-color: var(--bl-navy); }
/* Klingelt wie die anderen, eine Stufe später als WhatsApp, damit die drei
   nacheinander und nicht als Block wackeln. */
.dial-fab { animation: bell-nudge 1.5s ease-in-out 3; }
.dial-fab svg { animation: bell-shake 1.5s ease-in-out 3; }
.dial-fab::after { animation: bell-ring 1.5s ease-out 3; }
.dial-fab,
.dial-fab svg,
.dial-fab::after { animation-delay: 1.6s; }
.dial-fab:hover,
.dial-fab:focus-visible { animation: none; transform: translateY(-2px); }
.dial-fab:hover svg,
.dial-fab:focus-visible svg,
.dial-fab:hover::after,
.dial-fab:focus-visible::after { animation: none; }

/* Der Telefonknopf im Fließtext: ein Knopf, kein Link, weil Anrufen hier die
   Handlung ist und kein Verweis. */
.dial-btn { display: inline-flex; align-items: center; gap: 10px; margin-top: 4px; }
.dial-btn svg { width: 18px; height: 18px; fill: currentColor; display: block; }

/* Belle herself: her face, the main button, at the end of the row.

   It was a blue pill with a bell and "Speak to Belline" beside it; the founder
   asked for her face instead (15 Oct 2026), the still her video bubble rests
   on, so the corner shows one Belle whether her video came or not: the same
   96px, the same 3px of page colour and the brand blue round it that her
   landed bubble wears. The bell stays underneath, on the blue: it
   is what shows if her picture cannot load (a blocked host, offline), so the
   button is never an empty circle. */
.bell-fab {
  width: var(--fab-face);
  height: var(--fab-face);
  background: var(--bl-blue);
  color: var(--bl-white);
  border: 3px solid var(--bl-ground);
  box-shadow: 0 0 0 2px var(--bl-blue), var(--site-shadow-fab);
}
.bell-fab:hover { background: var(--bl-blue-hover); }
.bell-fab svg { width: 27px; height: 27px; display: block; color: var(--bl-white); }
.bell-fab-face {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: 999px;
  object-fit: cover;
  object-position: 50% 22%;
  display: block;
}
.bell-fab::after { border-color: var(--bl-blue); }
/* They ring one after another, and the step is the period divided by how many
   of them there are — 1.5 / 5 = 0.3 — not a round half second.

   They were 0.7 / 1.2 / 1.7 / 2.3 / 2.3, which reads correctly written down
   and is wrong on screen: the animation repeats every 1.5s, so the bell's
   second beat falls at 2.2 and arrives with the telephone's first at 2.3. The
   founder caught the same arithmetic failing in the bubble's own row ("when
   the buttons vibrate, phone and Instagram vibrate at the same time", f27) —
   and here the telephone and Instagram had been given the same 2.3 besides.

   At 0.3 apart the five sit at 0.7, 1.0, 1.3, 1.6 and 1.9, whose offsets
   within the period are 0.7, 1.0, 1.3, 0.1 and 0.4 — five distinct phases, so
   no two coincide on any repeat. A sixth button means dividing by six. */
.bell-fab,
.bell-fab svg,
.bell-fab::after { animation-delay: 0.7s; }

/* The chat. Belline blue with the white bubble (founder, 15 Oct 2026: "the
   chat button is Belline blue"). It was paper with a contour, meant as the
   quieter of two — but beside Belle's own row, where the chat has been blue
   since f22, a white one read as a different product's button. */
.chat-fab {
  background: var(--bl-blue);
  color: var(--bl-white);
  border: 1px solid var(--bl-blue);
}
.chat-fab:hover { background: var(--bl-blue-hover); border-color: var(--bl-blue-hover); }
.chat-fab svg { width: 23px; height: 23px; display: block; color: var(--bl-white); }
.chat-fab::after { border-color: var(--bl-blue); }
.chat-fab,
.chat-fab svg,
.chat-fab::after { animation-delay: 1.0s; }

/* WhatsApp. Grün, weißer Hörer, grüner Ring — und das Wort daneben in Tinte:
   Weiß auf diesem Grün ist 1.98:1, was der axe-Lauf auf jeder Gewerbeseite als
   ernsten Kontrastfehler meldet; Tinte darauf ist 8.6:1. Der Hörer bleibt
   weiß, weil er das Zeichen ist, und ein Zeichen ist kein Text. */
.wa-fab {
  background: var(--bl-whatsapp);
  color: var(--bl-whatsapp-ink);
  border: 1px solid var(--bl-whatsapp);
}
.wa-fab svg { width: 23px; height: 23px; display: block; color: var(--bl-whatsapp-mark); }
.wa-fab::after { border-color: var(--bl-whatsapp); }
.wa-fab,
.wa-fab svg,
.wa-fab::after { animation-delay: 1.3s; }

/* Der Instagram-Knopf, über dem Telefon und damit oben auf dem Stapel.

   Dieselbe Form und dasselbe Maß wie WhatsApp darunter, aus demselben Grund:
   fünf Knöpfe in einer Reihe, von denen einer anders aussieht, wirken wie ein
   Fehler und nicht wie eine Rangfolge (Gründer, 5. Okt. 2026, über das
   Telefon).

   Instagrams Verlauf statt einer Volltonfarbe, weil die Marke so erkannt wird
   — dieselbe Begründung, aus der WhatsApp sein Grün behält. Der Verlauf wird
   hier gesetzt und nicht im SVG, damit der Knopfgrund und das Zeichen
   auseinandergehalten bleiben: das Zeichen ist weiß, der Grund trägt die
   Farbe.

   Der Ring nimmt Instagrams Magenta, die mittlere Farbe des Verlaufs — ein
   Ring mit Verlauf ginge nur über ein zweites Pseudo-Element, und ein Ring ist
   Beiwerk. */
.ig-fab {
  background: linear-gradient(
    45deg,
    var(--bl-instagram-1) 0%,
    var(--bl-instagram-2) 35%,
    var(--bl-instagram-3) 70%,
    var(--bl-instagram-4) 100%
  );
  color: var(--bl-instagram-mark);
  border: 1px solid transparent;
}
.ig-fab svg { width: 23px; height: 23px; display: block; color: var(--bl-instagram-mark); }
.ig-fab::after { border-color: var(--bl-instagram); }
.ig-fab,
.ig-fab svg,
.ig-fab::after { animation-delay: 1.9s; }

/* Beim Überfahren hört es auf zu klingeln — wer den Zeiger darauf hat, ist
   schon aufmerksam geworden, und weiter zu wackeln macht das Ziel kleiner.
   Jeder hört für sich auf. */
.bell-fab:hover,
.bell-fab:focus-visible,
.chat-fab:hover,
.chat-fab:focus-visible,
.wa-fab:hover,
.wa-fab:focus-visible { animation: none; transform: translateY(-2px); }
.bell-fab:hover svg,
.bell-fab:focus-visible svg,
.bell-fab:hover::after,
.bell-fab:focus-visible::after,
.chat-fab:hover svg,
.chat-fab:focus-visible svg,
.chat-fab:hover::after,
.chat-fab:focus-visible::after,
.wa-fab:hover svg,
.wa-fab:focus-visible svg,
.wa-fab:hover::after,
.wa-fab:focus-visible::after { animation: none; }

.ig-fab:hover,
.ig-fab:focus-visible { transform: translateY(-2px); }

/* On a phone the same row, 4px tighter to the corner and the icons 52px, as
   Belle's own row is there (embed-video.js): five of them still fit in 375px
   (4 x 52 + 96 + 4 x 10 + 16 = 360). */
@media (max-width: 900px) {
  .fabs {
    --fab: 52px;
    right: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  }
}

@media (prefers-reduced-motion: reduce) {
  .bell-fab,
  .bell-fab svg,
  .bell-fab::after,
  .chat-fab,
  .chat-fab svg,
  .chat-fab::after,
  .wa-fab,
  .wa-fab svg,
  .wa-fab::after,
  .ig-fab,
  .ig-fab svg,
  .ig-fab::after,
  .dial-fab,
  .dial-fab svg,
  .dial-fab::after { animation: none; }
  .bell-fab,
  .chat-fab,
  .wa-fab,
  .ig-fab,
  .dial-fab { transition: none; }
  .bell-fab::after,
  .chat-fab::after,
  .wa-fab::after,
  .ig-fab::after,
  .dial-fab::after { opacity: 0; }
}

/* When the three stand down.
   - has-video-bubble: Belle's circle takes this corner, and WhatsApp and the
     chat become the two round icons under her face; the bell has none,
     because voice is the face.
   - video-pending: a call is being placed, so the corner belongs to it.
   - body.try: that page has one call to action and the bubble's own icons, so
     a second bell reads as a mistake. */
/* Der Telefonknopf geht mit: wo Belles Blase steht, sind ihre eigenen
   Symbole die Knöpfe, und ein viertes freischwebendes Ding daneben ist genau
   das, was der Gründer in f21 gemeldet hat. */
body.has-video-bubble .bell-fab,
body.has-video-bubble .chat-fab,
body.has-video-bubble .wa-fab,
body.has-video-bubble .dial-fab,
body.has-video-bubble .ig-fab,
body.video-pending .bell-fab,
body.video-pending .chat-fab,
body.video-pending .wa-fab,
body.video-pending .dial-fab,
body.video-pending .ig-fab,
body.has-video-bubble .fabs,
body.video-pending .fabs,
body.try .bell-fab { display: none; }
/* And while the phone menu is open (site.js `nav-open`): the menu is the
   screen then, and the round buttons floated over its country and language
   selects, as Belle's landed strip would over its "Get started". They come
   back as it closes; a call in progress is never hidden. */
body.nav-open :is(.bell-fab, .chat-fab, .wa-fab, .ig-fab, .dial-fab),
body.nav-open .video-bubble[data-vb="corner"]:not(.is-call) { visibility: hidden; }

/* Der Chat braucht Höhe, das Gespräch nicht — ein Anruf ist eine Leiste, ein
   Chat ist ein Fenster. Auf dem Telefon ist er ein Blatt, das über die Seite
   hochfährt (weiter unten): 380 px Chat in einem 390-px-Gerät wären kein
   Panel, der ganze Schirm wäre ein zweites Fenster. */
.chat-dock {
  position: fixed;
  right: 26px;
  bottom: 26px;
  z-index: 50;
  width: min(384px, calc(100vw - 36px));
  height: min(544px, calc(100vh - 52px));
  /* Papier, wie das Panel darin — der Grund ist nur eine Sekunde sichtbar,
     während der Rahmen lädt, und eine schwarze Sekunde ist ein Aufblitzen. */
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 14px;
  box-shadow: var(--site-shadow-chat-dock);
}
/* Die Ecke rundet der Rahmen selbst, nicht der Behälter: mit overflow:hidden
   würde der Schließknopf, der zehn Pixel außerhalb sitzt, weggeschnitten. */
.chat-frame { width: 100%; height: 100%; border: 0; display: block; border-radius: 14px; }
/* Das Blatt und sein Griff gibt es nur auf dem Telefon; auf dem Schreibtisch
   ist der Chat weiter ein Fenster in der Ecke, und die Seite daneben ist ohnehin
   zu sehen. Die Knoten baut site.js immer — hier sind sie schlicht nicht da. */
.chat-veil, .chat-grab { display: none; }

/* --- Das Telefon, bevor die Leiste da ist ----------------------------------
 *
 * Bei 375 px lagen die Glocke und die Sprechblase mit ihren Beschriftungen
 * genau über dem Anruf im Hero — über "Listen" und über den Reitern. Bis die
 * Kaufleiste sie ablöst, werden beide zu runden Knöpfen ohne Text: dasselbe
 * Zeichen, ein Viertel der Fläche. Die Reiter dürfen nicht mehr umbrechen;
 * "RESTAURANTS" allein in einer zweiten Zeile sah nach einem Fehler aus. */
@media (max-width: 620px) {
  /* Die Position der drei Knöpfe auf dem Telefon steht weiter unten, im
     900px-Block, an einer einzigen Stelle. Hier stand eine zweite Fassung,
     die der spätere Block halb überschrieb: der Chat-Knopf landete 4px unter
     WhatsApp, sein Papierrand lag über dessen Kante, und WhatsApp sah beim
     Scrollen aus, als rutsche er dahinter. */

  /* `.call .call-tabs`, nicht `.call-tabs`: die Grundregel weiter unten
     setzt flex-wrap: wrap und stünde bei gleicher Spezifität später. */
  .call .call-tabs {
    flex-wrap: nowrap;
    gap: 18px;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .call .call-tabs::-webkit-scrollbar { display: none; }
  .call .call-tab { white-space: nowrap; flex-shrink: 0; }

  /* Drei Zahlen untereinander, nicht zwei und eine. */
  .facts-3 { grid-template-columns: 1fr; }
  .facts-3 .fact { padding-inline-start: 0; padding-inline-end: 0; border-inline-end: 0; border-bottom: 1px solid var(--rule-soft); }
  .facts-3 .fact:last-child { border-bottom: 0; }

  /* Ein Blatt, das hochfährt — kein zweites Fenster (Gründer, 18.09.2026).
     Der Chat nahm auf dem Telefon den ganzen Schirm ein: die Seite verschwand,
     und wer ihn schloss, wusste nicht mehr, wo er gewesen war. Jetzt liegt er
     als Blatt über der Seite, die Seite bleibt darunter sichtbar und an ihrer
     Stelle, ein Tippen daneben oder auf den Griff schließt ihn. */
  .chat-veil {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 49;
    background: rgba(17, 17, 17, 0.38);
    opacity: 0;
    animation: chat-veil-in 0.22s ease forwards;
    -webkit-tap-highlight-color: transparent;
  }
  .chat-dock {
    top: auto;
    right: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    /* Hoch genug für ein Gespräch, niedrig genug, dass die Seite darüber zu
       sehen bleibt: der Besucher bleibt, wo er war. */
    height: min(86dvh, calc(100dvh - 56px));
    border-radius: 18px 18px 0 0;
    border-bottom: 0;
    transform: translateY(100%);
    animation: chat-sheet-up 0.26s cubic-bezier(0.22, 0.8, 0.28, 1) forwards;
    padding-top: 22px;
    overflow: hidden;
  }
  .chat-frame { border-radius: 0; height: 100%; }
  /* Der Griff: sagt, dass das Blatt zum Schließen ist, und ist selbst die Fläche dafür. */
  .chat-grab {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 22px;
    display: grid;
    place-items: center;
    padding: 0;
    border: 0;
    background: var(--paper);
    cursor: pointer;
    touch-action: none;
  }
  .chat-grab::before {
    content: "";
    width: 40px;
    height: 4px;
    border-radius: 999px;
    background: var(--bl-rule-strong);
  }
  .chat-dock .call-shut {
    top: 30px;
    right: 12px;
    border-color: var(--rule);
    background: var(--paper);
    color: var(--ink-2);
  }
}
@keyframes chat-sheet-up { to { transform: translateY(0); } }
@keyframes chat-veil-in { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .chat-dock { animation-duration: 0.01ms; }
  .chat-veil { animation-duration: 0.01ms; }
}

/* --- Video ------------------------------------------------------------------
 *
 * Only on screen when the video receptionist is switched on for our own venue
 * (site.js loads embed-video.js, which makes the bubble). The bubble takes the
 * corner the three floating buttons had, at the call's own size from the first
 * load, and they step aside: WhatsApp and the chat become the two round icons
 * under Belle's face, and the bell has none, because voice is the face. A call
 * happens in the same circle; there is no dock and no panel. Its size comes
 * from embed-video.js (the call circle), not from here. The rule that stands
 * the three floating buttons down lives with them, under "The floating
 * buttons". */
/* site.js: the bubble rests in the hero and is carried to the corner by the
   scroll (`vb-travel`; see "Belle, carried" at the end of this file). It
   floats instead — full call size, fixed in the corner — for a call started
   while the hero's place is out of view. */
.video-bubble.vb-leaving { visibility: hidden; }
.video-bubble.vb-float:not(.is-pip) {
  position: fixed;
  z-index: 41;
  right: 24px;
  bottom: calc(24px + env(safe-area-inset-bottom, 0px));
}
@media (max-width: 900px) {
  .video-bubble.vb-float:not(.is-pip) {
    right: 20px;
    bottom: calc(20px + env(safe-area-inset-bottom, 0px));
  }
}
/* --- Das angedockte Gespräch ------------------------------------------------ */

.call-dock {
  position: fixed;
  right: 26px;
  bottom: 26px;
  z-index: 50;
  width: min(400px, calc(100vw - 36px));
  background: var(--paper);
  border: 1px solid var(--ink);
  border-radius: 14px;
  box-shadow: var(--site-shadow-call-dock);
}
.call-frame { width: 100%; height: 76px; border: 0; display: block; }
.call-shut {
  position: absolute;
  top: -10px;
  right: -10px;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1px solid var(--ink);
  background: var(--paper);
  color: var(--ink-2);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}

@media (max-width: 1000px) {
  .plans { grid-template-columns: 1fr; }
  .plan { padding: 30px 0; border-inline-end: 0; border-bottom: 1px solid var(--rule-soft); }
  .plan.is-best { margin-top: 0; }
  .terms,
  .terms.terms-4 { grid-template-columns: 1fr; gap: 24px; }
  .module-groups { grid-template-columns: 1fr; }
  .plates { grid-template-columns: 1fr; gap: 40px; }
}

@media (max-width: 900px) {
  .hero-in { grid-template-columns: 1fr; gap: 46px; }
  /* Unter dem Text, und nicht mehr hochkant: bei 4:5 wäre das Bild auf einem
     Telefon anderthalb Bildschirme hoch, bevor die drei Zahlen kommen. */
  .hero h1 { max-width: 16ch; }
  .book-grid { grid-template-columns: 1fr; gap: 34px; }
  .f-row { grid-template-columns: 1fr; }
  .script .caller p { font-size: 1.25rem; }
  .compare { font-size: 1.3rem; text-align: start; }
  /* (The three floating buttons become a stack of circles at this width; that
     rule lives with them, under "The floating buttons".) */
  .call-dock { right: 16px; left: 16px; width: auto; }
}

@media (prefers-reduced-motion: reduce) {
  .rise,
  .call-wave i { animation: none; }
}

/* --- Handelsseiten ----------------------------------------------------------
   Die vier Seiten unter /dental, /clinics, /salons, /restaurants. Sie sind die
   Startseite mit anderem Wissen, also erben sie deren Bausteine — Hero,
   .script, .plate, .btn — und brauchen nur zwei eigene Muster.

   Kein zweiter Satz Karten: was hier dazukommt, sind Haarlinien wie überall
   sonst. */

/* Was der Kalender dieses Gewerbes tatsächlich enthält. Vier Bedingungen,
   nebeneinander gesetzt statt untereinander aufgezählt — sie sind gleichrangig
   und keine Reihenfolge, deshalb ein Raster und keine Nummern. */
.knows {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 56px;
  margin-top: 52px;
  border-top: 1px solid var(--rule);
}
.knows > div { padding: 28px 0; border-bottom: 1px solid var(--rule-soft); }
.knows h3 {
  margin: 0 0 9px;
  font-family: var(--serif);
  font-weight: 400;
  font-size: 1.3rem;
  letter-spacing: -0.015em;
}
.knows p { margin: 0; font-size: 0.92rem; color: var(--ink-2); max-width: 46ch; }

/* Die Grenze: links der Satz, rechts der Anruf, an dem er sich beweist. */
.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 64px;
  align-items: start;
}
.split .btn { margin-top: 30px; }

/* Dieselbe Marke wie in .handled-row: was ein Mensch übernimmt, steht in
   Messing. */
.script-out .tag.human { color: var(--brass); }

/* Ein einzelnes Bild, nicht eines von dreien im Raster. `.plate` wird zweimal
   gesetzt und die spätere Regel nimmt den Außenabstand wieder weg; hier kommt
   er zurück, ohne die Reihe auf der Startseite anzufassen. */
.plate.solo { margin-top: 64px; }

@media (max-width: 900px) {
  .knows { grid-template-columns: 1fr; gap: 0; margin-top: 40px; }
  .split { grid-template-columns: 1fr; gap: 42px; }
}

/* --- Der Anruf, der läuft ---------------------------------------------------
 *
 * Im Hero stand zuletzt ein gesetztes Gespräch, das stillstand. Es las sich
 * wie ein Screenshot, und ein Screenshot ist genau das, was diese Seite nicht
 * sein will: das Produkt ist eine Stimme, die antwortet, und ein Bild davon
 * überzeugt niemanden.
 *
 * Also läuft es wieder — dieselbe Mechanik wie vorher (site.js, unverändert),
 * nur nicht mehr als dunkles Chatfenster, sondern in der Typografie des Rests
 * der Seite: Haarlinien, der Anrufer in der Antiqua, Belline in der Grotesk.
 * Die Zeilen kommen in dem Tempo, in dem sie gesprochen werden, der Status
 * sagt "Checking the book", wenn das Ding tatsächlich den Kalender liest, und
 * "Listen" spielt die echte Aufnahme.
 *
 * Der Ruhezustand ist die fertige Unterhaltung: site.js malt sie sofort und
 * spielt sie erst, wenn sie im Bild ist. Wer nie scrollt, sieht trotzdem
 * alles — wie bei .rise ist die Bewegung eine Zugabe, keine Bedingung. */

.call { margin: 8px 0 0; border-top: 1px solid var(--ink); }

/* Die Reiter. Auf der Startseite vier Gewerbe, auf einer Gewerbeseite die
   beiden Seiten derselben Leitung — gebucht und abgelehnt. */
.call-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
  padding: 16px 0 0;
}
.call-tab {
  appearance: none;
  background: none;
  border: 0;
  border-bottom: 1px solid transparent;
  padding: 0 0 5px;
  font: inherit;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  cursor: pointer;
}
.call-tab:hover { color: var(--ink); }
.call-tab[aria-selected="true"] { color: var(--brass); border-bottom-color: var(--brass); }

/* Kopfzeile: die Uhrzeit, was gerade passiert, und der Knopf für den Ton. */
.call-head {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px 0 20px;
  font-size: 0.8rem;
  color: var(--ink-3);
}
.call-status {
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brass);
}
.call-line { margin-inline-start: 2px; }
.call-listen {
  margin-inline-start: auto;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 15px;
  border-radius: 999px;
  border: 1px solid var(--rule);
  background: none;
  font: inherit;
  font-size: 0.78rem;
  color: var(--ink-2);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
  white-space: nowrap;
}
.call-listen:hover { border-color: var(--ink); color: var(--ink); }
.call-listen[hidden] { display: none; }
.call-listen[aria-pressed="true"] { border-color: var(--brass); color: var(--brass); }

/* Die Kurve. Neun Striche, die nur laufen, während Belline spricht — das ist
   der einzige Unterschied zwischen "es antwortet" und "es steht da". */
.call-wave { display: inline-flex; align-items: flex-end; gap: 3px; height: 15px; }
.call-wave i {
  display: block;
  width: 2px;
  height: 4px;
  background: var(--ink-3);
  border-radius: 1px;
  transition: background 0.2s ease;
}
[data-speaking="true"] .call-wave i {
  background: var(--brass);
  animation: call-wave 0.9s ease-in-out infinite;
}
.call-wave i:nth-child(2) { animation-delay: 0.08s; }
.call-wave i:nth-child(3) { animation-delay: 0.16s; }
.call-wave i:nth-child(4) { animation-delay: 0.24s; }
.call-wave i:nth-child(5) { animation-delay: 0.32s; }
.call-wave i:nth-child(6) { animation-delay: 0.40s; }
.call-wave i:nth-child(7) { animation-delay: 0.48s; }
.call-wave i:nth-child(8) { animation-delay: 0.56s; }
.call-wave i:nth-child(9) { animation-delay: 0.64s; }
@keyframes call-wave {
  0%, 100% { height: 4px; }
  50% { height: 15px; }
}

/* Der Mitschnitt. Dieselben zwei Stimmen in zwei Schriften wie im gesetzten
   Gespräch — ein gedrucktes Interview, kein Chatfenster mit Sprechblasen.

   min-height, damit die Seite nicht springt, während die Zeilen eintreffen:
   ein Layout, das unter dem Text wegrutscht, liest sich als Fehler. */
.call-body { min-height: 268px; }
.call-body .turn { padding: 0 0 22px; }
.call-body .who {
  display: block;
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 7px;
}
.call-body .said { display: block; }
.call-body .caller .said {
  font-family: var(--serif);
  font-size: 1.46rem;
  line-height: 1.24;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.call-body .agent {
  padding-inline-start: 26px;
  border-inline-start: 1px solid var(--rule);
}
.call-body .agent .said { font-size: 1rem; color: var(--ink-2); line-height: 1.5; }

/* Jede Zeile kommt von unten herein, nie aus dem Nichts — dieselbe Regel wie
   bei .rise: bewegen, nicht einblenden. */
.call-body .turn,
.call-body .call-out { animation: call-in 0.34s cubic-bezier(0.2, 0.7, 0.2, 1) both; }
@keyframes call-in {
  from { transform: translateY(8px); }
  to { transform: none; }
}

.call-out {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding-top: 18px;
  border-top: 1px solid var(--rule);
  font-size: 0.86rem;
  color: var(--ink-2);
}
.call-out .tag {
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brass);
  border: 1px solid var(--brass-soft);
  border-radius: 999px;
  padding: 5px 11px;
  white-space: nowrap;
}
.call-out .tag.human { color: var(--ink-2); border-color: var(--rule); }

@media (max-width: 900px) {
  /* Kleiner reserviert, aber reserviert: ohne min-height wächst das Feld,
     während die Zeilen eintreffen, und alles darunter rutscht mit. Ein
     Layout, das unter dem Daumen wegspringt, liest sich als Fehler. */
  .call-body { min-height: 210px; }
  .call-body .caller .said { font-size: 1.3rem; }
  .call-head { flex-wrap: wrap; gap: 10px 12px; }
  .call-listen { margin-inline-start: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .call-body .turn,
  .call-body .call-out,
  [data-speaking="true"] .call-wave i { animation: none; }
}

/* --- Die Kopfzeile eines Abschnitts -----------------------------------------
 *
 * Überschrift links, Einleitung rechts, beide auf derselben Grundlinie unten.
 *
 * Vorher stand beides untereinander in der linken Hälfte und die rechte Hälfte
 * blieb leer. Das liest sich nicht als Großzügigkeit, sondern als eine Seite,
 * die für ein Telefon gebaut und auf einem Laptop geöffnet wurde: die Schrift
 * wirkt klein, weil das Maß halb so breit ist wie der Bildschirm.
 *
 * align-items: end, damit die letzte Zeile der Einleitung mit der letzten
 * Zeile der Überschrift abschließt — zwei Spalten, die oben beginnen, aber
 * unten unterschiedlich enden, sehen aus, als hätte sie niemand gesetzt. */
.sec-head {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: 24px 64px;
  align-items: end;
}
.sec-head > div { min-width: 0; }
.sec-head .eyebrow { margin-bottom: 18px; }
.sec-head .sec-lead { margin: 0; max-width: 46ch; }
/* No single word alone on the last line ("…reach / it."). */
.lead, .sec-lead { text-wrap: pretty; }

@media (max-width: 900px) {
  .sec-head { grid-template-columns: 1fr; gap: 22px; }
  .sec-head .sec-lead { max-width: none; }
}

/* Die drei Gewerbe als Notizen nebeneinander, ohne Bild. Der Unterschied
   zwischen einem Tisch und einem Termin ist eine Sache von Sätzen, nicht von
   Fotos — und drei mittelmäßige Fotos nebeneinander sagen weniger als eins,
   das etwas kann. */
.trades {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 40px;
  margin-top: 56px;
  padding-top: 34px;
  border-top: 1px solid var(--rule);
}
.trades h3 {
  margin: 0 0 10px;
  font-family: var(--serif);
  font-weight: 400;
  font-size: 1.34rem;
  letter-spacing: -0.015em;
}
.trades p { margin: 0; font-size: 0.94rem; color: var(--ink-2); }

/* Das eine Bild. Hochformat auf ein Band beschnitten: die Glocke sitzt im
   unteren Drittel der Aufnahme, also zeigt object-position dorthin statt in
   die Mitte, wo nur Decke wäre. */
.plate img { object-fit: cover; }

/* --- Die vier Gewerbe --------------------------------------------------------
 *
 * Vorher: vier Links in einer Zeile und darunter ein großes Foto einer leeren
 * Rezeption. Das Foto hat das Problem ein zweites Mal erzählt, das die
 * Überschrift schon erzählt hatte, und die vier Links — das Einzige in diesem
 * Abschnitt, das jemand anklickt — unter die Falz geschoben.
 *
 * Jetzt vier Karten. Vier Spalten, dann zwei, dann eine: bei drei Spalten
 * stünde eine Karte allein in der letzten Zeile. Die Ziffer ist keine
 * Dekoration — sie sagt, dass es genau vier sind und dass man sie zählen kann,
 * bevor man sie liest.
 */

@media (max-width: 900px) {
  .trades { grid-template-columns: 1fr; gap: 28px; margin-top: 40px; }
}


/* --- Die Antiqua in kleinen Graden ------------------------------------------
 * Fraunces' optische Achse macht den Strich kräftiger, je kleiner der Grad —
 * aber sie kann das Gewicht nicht erraten. Alles zwischen 20 und 30 Pixeln
 * ist hier eine Zwischenüberschrift oder eine Zahl, die gelesen werden muss,
 * und bekommt deshalb 500 statt 400. Die großen Überschriften bleiben bei
 * 400: dort ist der Grad das Gewicht.
 *
 * Gesammelt an einer Stelle statt an zwölf, damit "die Antiqua ist zu dünn"
 * eine Zeile zu ändern ist und keine Suche.
 */
.fact .n,
.step .num,
.handled-row .q,
.plate figcaption strong,
.trades h3,
.knows h3,
.faq summary,
.compare,
.script-head .at,
.script .caller p,
.call-head .call-line,
.call-body .caller .said,
.plan-price .amt,
.sec-head .k,
.rule-row .k {
  font-weight: 500;
}

/* Die kleinsten Vorkommen — Uhrzeit und Betrag in einer Zeile mit Grotesk —
   brauchen am meisten, weil daneben eine Grotesk mit gleichmäßigem Strich
   steht und jeder Unterschied als "blass" gelesen wird. */
.script-head .at,
.call-head .call-line { font-weight: 600; }

/* --- Kaufen ----------------------------------------------------------------
 *
 * Eine Handlung, überall dieselbe, und sie sieht aus wie eine Handlung.
 *
 * Vorher standen im Hero zwei gleich große Knöpfe nebeneinander — und der
 * gefüllte war die Demo. Die auffälligste Handlung auf der Startseite war
 * "kauf noch nicht". Die Demo ist jetzt ein Link darunter: sie überzeugt,
 * aber sie verkauft nicht, und sie darf dem Knopf, der es tut, nicht die
 * Aufmerksamkeit wegnehmen.
 */
.btn-quiet {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 0.95rem;
  color: var(--ink-2);
  text-decoration: none;
  border-bottom: 1px solid var(--brass-soft);
  padding: 0 0 4px;
  align-self: center;
}
.btn-quiet:hover { border-bottom-color: var(--brass); color: var(--ink); }
.btn-quiet svg { width: 17px; height: 17px; color: var(--brass); }

/* Drei Zahlen statt vier, und alle drei sind Ergebnisse. "Unter 1s bis zum
   ersten gesprochenen Wort" ist eine Kennzahl für einen Entwickler. */
.facts-3 { grid-template-columns: repeat(3, 1fr); }

/* Vier Fähigkeiten, nicht zwölf Karten. */
.does {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 64px;
  margin-top: 52px;
  border-top: 1px solid var(--rule);
}
.does > div { padding: 30px 0; border-bottom: 1px solid var(--rule-soft); }
.does h3 {
  margin: 0 0 9px;
  font-family: var(--serif);
  font-weight: 500;
  font-size: 1.34rem;
  letter-spacing: -0.015em;
}
.does p { margin: 0; font-size: 0.96rem; color: var(--ink-2); max-width: 42ch; }

/* --- Ein Preis -------------------------------------------------------------
 * Drei Pläne und ein Umschalter sind vier Entscheidungen vor einem Kauf. Der
 * Preis, der für fast jeden gilt, steht vorn; die beiden anderen sind ein
 * Satz für die Minderheit, die sie braucht.
 */
.price-one {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.75fr);
  gap: 64px;
  margin-top: 10px;
  align-items: start;
}
.price-list { list-style: none; padding: 0; margin: 26px 0 0; }
.price-list li {
  position: relative;
  padding-inline-start: 20px;
  margin-bottom: 11px;
  font-size: 0.96rem;
  color: var(--ink-2);
}
.price-list li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 0.62em;
  width: 8px;
  height: 1px;
  background: var(--brass);
}
.price-aside {
  padding: 28px 0 0;
  border-top: 1px solid var(--rule);
}
.price-aside h3 {
  margin: 0 0 10px;
  font-family: var(--serif);
  font-weight: 500;
  font-size: 1.2rem;
  letter-spacing: -0.015em;
}
.price-aside p { font-size: 0.92rem; margin: 0 0 16px; }
.price-aside details { border-top: 1px solid var(--rule-soft); padding-top: 14px; }
.price-aside summary {
  list-style: none;
  cursor: pointer;
  font-size: 0.86rem;
  color: var(--ink-2);
}
.price-aside summary::-webkit-details-marker { display: none; }
.price-aside summary::after { content: " +"; color: var(--brass); }
.price-aside details[open] summary::after { content: " –"; }
.price-aside details p { font-size: 0.86rem; margin-top: 12px; color: var(--ink-3); }

/* --- Der Beweis im Abschluss ----------------------------------------------- */
.proof {
  margin-top: 56px;
  padding-top: 30px;
  border-top: 1px solid var(--rule);
  max-width: 54ch;
}
.proof h3 {
  margin: 0 0 10px;
  font-family: var(--serif);
  font-weight: 500;
  font-size: 1.4rem;
  letter-spacing: -0.015em;
}
.proof p { font-size: 0.96rem; margin: 0 0 18px; }
.dial {
  display: inline-block;
  font-family: var(--serif);
  font-weight: 500;
  font-size: 1.7rem;
  letter-spacing: -0.015em;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid var(--brass-soft);
  padding-bottom: 3px;
}
.dial:hover { border-bottom-color: var(--brass); }
.proof ul { list-style: none; padding: 0; margin: 20px 0 0; }
.proof ul li {
  font-size: 0.9rem;
  color: var(--ink-3);
  padding-inline-start: 20px;
  position: relative;
  margin-bottom: 7px;
}
.proof ul li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 0.6em;
  width: 8px;
  height: 1px;
  background: var(--brass-soft);
}

@media (max-width: 900px) {
  .does { grid-template-columns: 1fr; gap: 0; margin-top: 40px; }
  .price-one { grid-template-columns: 1fr; gap: 40px; }
  .facts-3 { grid-template-columns: 1fr 1fr; }
  .facts-3 .fact:last-child { border-inline-end: 0; padding-inline-start: 0; }
  .cta-row { gap: 20px; }
  .btn-quiet { align-self: flex-start; }

  /* Die drei Knöpfe bleiben auf dem Telefon immer da — keine Leiste, die sie
     beim Scrollen ablöst. Der Abschluss bekommt unten Platz, damit der
     Stapel aus drei Kreisen die letzte Zeile nicht verdeckt. */
  .closer { padding-bottom: 220px; }
}

/* Die beiden größeren Pläne und die Minutendefinition stehen zusammengeklappt
   in der Randspalte. Sie müssen auf der Seite stehen — check:billing bricht
   den Build, wenn eine lebende Funktion fehlt — aber sie müssen nicht vor dem
   Knopf stehen. */
.price-aside details + details { margin-top: 10px; }
.price-aside .price-list { margin-top: 12px; }
.price-aside .price-list li { font-size: 0.86rem; margin-bottom: 7px; color: var(--ink-3); }
.price-aside summary { font-weight: 500; color: var(--ink); padding: 4px 0; }

/* --- Wo sie antwortet --------------------------------------------------------
 * Zwei Kanäle, weil zwei stimmen. WhatsApp ist gebaut, ausgeliefert und
 * getestet und hängt an keiner Nummer — es steht deshalb nicht auf der Seite.
 * Am Tag, an dem eine Nummer antwortet, bekommt dieser Block eine dritte
 * Spalte statt einer Entschuldigung.
 */
.channels {
  display: grid;
  /* Drei, seit die Website auch getippt beantwortet wird. Bei zwei Spalten
     stünde die dritte Karte allein in einer eigenen Zeile — dieselbe Angabe,
     aber optisch ein Nachtrag statt ein gleichwertiger Kanal. */
  /* Vier, seit WhatsApp dazugekommen ist: zwei mal zwei, damit keine Karte
     allein in einer Zeile steht. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 48px;
  margin-top: 52px;
  border-top: 1px solid var(--rule);
}
.channels > div { padding: 32px 0; border-bottom: 1px solid var(--rule-soft); }
.channel-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin: 0 0 12px; }
.channels h3 {
  margin: 0;
  font-family: var(--serif);
  font-weight: 600;
  font-size: 1.5rem;
  letter-spacing: -0.015em;
}
.channels p { margin: 0 0 14px; font-size: 0.96rem; max-width: 44ch; }
/* Die Zeile, die die Angst nimmt: wie viel Arbeit ist das für mich? */
.channel-how {
  margin: 0 !important;
  font-size: 0.86rem !important;
  color: var(--brass);
}

/* --- Status badges (Direction C) --------------------------------------------
   Available: Lagoon on its tint, 5.30:1. Beta: desk brass on brass tint,
   4.99:1. Coming soon: stone outline, 5.22:1 on ivory. Request: ink outline.
   Lagoon is for states only. Mirrored in src/app/globals.css. */
.state {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 26px;
  padding: 0 11px;
  border-radius: var(--bl-radius-pill);
  border: 1px solid transparent;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
}
.state-available { background: var(--bl-success-tint); color: var(--bl-success); }
.state-available::before { content: ""; width: 6px; height: 6px; border-radius: 999px; background: currentColor; }
.state-beta { background: var(--bl-blue-tint); color: var(--bl-blue-hover); }
.state-soon { border-color: var(--bl-rule-strong); color: var(--bl-muted); font-weight: 500; }
.state-request { border-color: var(--bl-ink-900); color: var(--bl-ink-900); }

/* Was noch nicht läuft, steht trotzdem da — nur eben als Notiz und nicht als
   Versprechen. Ruhiger gesetzt als die Kanäle darüber, weil es keiner ist. */
.channel-note {
  margin: 26px 0 0;
  font-size: 0.9rem;
  color: var(--ink-3);
  max-width: 64ch;
  line-height: 1.65;
}

/* Drei oder eins, nichts dazwischen: zwei Spalten für drei Karten lassen
   immer eine allein in der letzten Zeile stehen. */
@media (max-width: 760px) {
  .channels { grid-template-columns: 1fr; gap: 0; margin-top: 40px; }
}

/* Der Weg aus dem Aufklapper heraus. Zwei Pläne standen dort lesbar und
   unkaufbar: die Funktionen aufgelistet, kein Knopf nirgends. */
.plan-pick {
  display: inline-block;
  margin-top: 14px;
  font-size: 0.88rem;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid var(--brass-soft);
  padding-bottom: 3px;
}
.plan-pick:hover { border-bottom-color: var(--brass); }

/* ===========================================================================
   Homepage, September 2026: "works with the tools you already use".
   Everything below is the landing page only. Tokens from brand/tokens.css;
   no new colours. Panels are flat (no shadows), as the brand asks.
   =========================================================================== */

.vh {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* Three plain facts under the hero. */
.plain-facts {
  list-style: none;
  margin: 88px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border-top: 1px solid var(--rule);
}
.plain-facts li {
  padding: 26px 28px 0;
  border-inline-end: 1px solid var(--rule-soft);
  font-size: 0.94rem;
  color: var(--ink-3);
}
.plain-facts li:first-child { padding-inline-start: 0; }
.plain-facts li:last-child { padding-inline-end: 0; border-inline-end: 0; }
.plain-facts strong {
  display: block;
  margin-bottom: 6px;
  font-family: var(--bl-font-display);
  font-size: 1.4rem;
  font-weight: 650;
  line-height: 1.15;
  letter-spacing: var(--bl-track-h2);
  color: var(--ink);
}

/* --- The problem ------------------------------------------------------------ */
.problem .problem-h {
  font-size: clamp(2.1rem, 1.2rem + 3vw, 3.7rem);
  max-width: 19ch;
}
.problem-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 64px;
  margin-top: 56px;
  border-top: 1px solid var(--rule);
}
.problem-grid > div { padding-top: 26px; }
.problem-grid h3,
.stop h3,
.works h3 {
  margin: 0 0 10px;
  font-family: var(--bl-font-display);
  font-size: 1.3rem;
  font-weight: 650;
  letter-spacing: var(--bl-track-h2);
}
.problem-grid p { margin: 0; }
.problem-coda {
  margin: 48px 0 0;
  max-width: 44ch;
  font-family: var(--bl-font-display);
  font-size: clamp(1.3rem, 1rem + 1vw, 1.7rem);
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.015em;
  color: var(--ink);
}

/* --- Where it answers: four channels with icons ----------------------------- */
.channels-4 {
  list-style: none;
  padding: 0;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0;
}
.channels-4 > li {
  display: flex;
  flex-direction: column;
  padding: 30px 24px 32px;
  border-inline-end: 1px solid var(--rule-soft);
  border-bottom: 1px solid var(--rule-soft);
}
.channels-4 > li:first-child { padding-inline-start: 0; }
.channels-4 > li:last-child { padding-inline-end: 0; border-inline-end: 0; }
.channels-4 h3 { font-size: 1.22rem; }
.channels-4 .channel-how { margin-top: auto !important; padding-top: 6px; }
.channels-4 .channel-how a { color: var(--ink); text-underline-offset: 3px; }
/* Three while the video receptionist is off (src/lib/site-flags.ts adds it as the fourth). */
@media (min-width: 1101px) {
  .channels-4.channels-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* And three again once there are five.

     Instagram made a fifth card, and five in a four-column grid is four and
     then one alone underneath — which reads as a card that did not fit rather
     than a channel of equal standing. Twice from the founder (f25: "Five
     columns doesn't look good"; f26: "Still five columns not looking good").

     Three columns makes it three and two, and a row of two under a row of
     three looks chosen. `:has()` counts the cards so nothing has to pass a
     class down: the day a sixth channel arrives it becomes three and three on
     its own. */
  .channels-4:has(> li:nth-child(5)) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.ico {
  width: 28px;
  height: 28px;
  margin-bottom: 18px;
  fill: none;
  stroke: var(--ink);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/*
  Belle's own bubble, where the video card used to have a camera (founder,
  6 Oct 2026). Her face in the blue ring — the thing a visitor meets in the
  corner of this page — rather than a drawing of the medium.

  A background image on a span, not an `<image>` inside the inline SVG, and the
  reason is the flag system rather than taste. The card is a `video.avatar`
  swap (src/lib/site-flags.ts), the build fingerprints asset filenames, and a
  swap carrying `/video/faces/<id>.jpg` would be inserted with a path the built
  page does not use — and, worse, the reverse swap could never find its needle
  in a built page, so serving the flag-on build with video off would leave the
  card in. The URL belongs in the stylesheet, where the build rewrites it like
  every other asset, and the swap carries a class name that nothing hashes.
*/
/* The rule itself is `#channels .ico-belle`, below, beside the one it has to
   out-rank: `#channels .ico` sets the pale tile with the `background`
   shorthand, which resets `background-image` to none. */
#channels .cta-row { margin-top: 36px; }

@media (max-width: 1100px) {
  .hero-demo { grid-template-columns: minmax(0, 1fr); gap: 52px; }
  .channels-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .channels-4 > li,
  .channels-4 > li:first-child,
  .channels-4 > li:last-child { padding: 28px 24px 30px; border-inline-end: 1px solid var(--rule-soft); }
  .channels-4 > li:nth-child(2n) { padding-inline-end: 0; border-inline-end: 0; }
  .channels-4 > li:nth-child(2n + 1) { padding-inline-start: 0; }
}
@media (max-width: 760px) {
  .plain-facts { grid-template-columns: 1fr; margin-top: 56px; }
  .plain-facts li,
  .plain-facts li:first-child,
  .plain-facts li:last-child { padding: 20px 0; border-inline-end: 0; border-bottom: 1px solid var(--rule-soft); }
  .plain-facts li:last-child { border-bottom: 0; }
  .problem-grid { grid-template-columns: 1fr; margin-top: 40px; }
  .channels-4 { grid-template-columns: 1fr; }
  .channels-4 > li,
  .channels-4 > li:first-child,
  .channels-4 > li:last-child,
  .channels-4 > li:nth-child(2n),
  .channels-4 > li:nth-child(2n + 1) { padding: 26px 0 28px; border-inline-end: 0; }
}

/* --- Works with how you already work -------------------------------------- */
.works-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0 48px;
  margin-top: 52px;
  border-top: 1px solid var(--rule);
}
.works-grid > div { padding-top: 26px; }
.works-grid p { margin: 0; font-size: 0.98rem; }
.works .routes-h {
  margin: 64px 0 0;
  font-family: inherit;
  letter-spacing: 0;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--ink);
}
.routes { margin: 16px 0 0; border-top: 1px solid var(--rule); }
.routes > div {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  gap: 8px 48px;
  padding: 18px 0;
  border-bottom: 1px solid var(--rule-soft);
}
.routes dt {
  font-family: var(--bl-font-display);
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.routes dd { margin: 0; font-size: 0.96rem; color: var(--ink-2); max-width: 62ch; }

/* --- It knows when to stop ------------------------------------------------- */
.stop-rows { margin-top: 52px; border-top: 1px solid var(--rule); }
.stop-rows > div {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  gap: 8px 48px;
  padding: 24px 0;
  border-bottom: 1px solid var(--rule-soft);
}
.stop-rows h3 { margin: 0; }
.stop-rows p { margin: 0; font-size: 0.98rem; }
.stop-small { margin: 20px 0 0; font-size: 0.86rem; color: var(--ink-3); }
.cta-aside { align-self: center; font-size: 0.92rem; color: var(--ink-3); }

/* --- Three steps: a real sequence, so real numbers ------------------------- */
.steps-home { list-style: none; padding: 0; margin-top: 52px; }
.steps-home .num {
  font-family: var(--bl-font-display);
  font-size: 2.6rem;
  font-weight: 700;
  line-height: 1;
  color: var(--ink);
}
.steps-home h3 {
  font-family: var(--bl-font-display);
  font-size: 1.3rem;
  font-weight: 650;
  letter-spacing: var(--bl-track-h2);
  line-height: 1.2;
}
.steps-home p { font-size: 0.98rem; }
#how .cta-row { margin-top: 44px; }

/* --- The calculator as one sentence --------------------------------------- */
.roi.roi-sentence-form {
  max-width: none;
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: 32px 64px;
  align-items: end;
  margin-top: 52px;
  padding-top: 40px;
  border-top: 1px solid var(--rule);
}
.roi-sentence {
  margin: 0;
  max-width: 26ch;
  font-family: var(--bl-font-display);
  font-size: clamp(1.55rem, 1rem + 1.9vw, 2.4rem);
  font-weight: 500;
  line-height: 1.55;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.roi-field { display: inline-block; }
.roi-field input {
  width: calc(3ch + 0.7em);
  min-height: 44px;
  padding: 0 0.3em;
  font: inherit;
  font-size: max(1em, 16px);
  font-variant-numeric: tabular-nums;
  text-align: center;
  color: var(--ink);
  background: var(--bl-ground);
  border: 1px solid var(--bl-rule-strong);
  border-radius: var(--bl-radius-input);
  line-height: 1.2;
  -moz-appearance: textfield;
  appearance: textfield;
}
.roi-field-wide input { width: calc(4ch + 0.7em); }
.roi-field input::-webkit-outer-spin-button,
.roi-field input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.roi-field input:focus-visible,
.roi-pick select:focus-visible {
  outline: var(--bl-focus);
  outline-offset: var(--bl-focus-offset);
  border-color: var(--bl-success);
}
.roi-result { min-width: 0; }
.roi-sentence-form .roi-out {
  margin: 0 0 14px;
  max-width: none;
  font-family: var(--bl-font-display);
  font-size: clamp(2.4rem, 1.3rem + 3.6vw, 4.6rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: var(--bl-track-h1);
  color: var(--ink);
}
.roi-detail { margin: 0 0 18px; font-size: 1rem; color: var(--ink-2); }
.roi-pick { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; font-size: 0.95rem; color: var(--ink-2); }
.roi-pick select {
  max-width: 100%;
  min-height: 44px;
  padding: 8px 12px;
  font: inherit;
  font-size: 1rem;
  color: var(--ink);
  background: var(--bl-ground);
  border: 1px solid var(--bl-rule-strong);
  border-radius: var(--bl-radius-input);
}
#worth .roi-fine { margin-top: 28px; }

/* --- FAQ note and closer ------------------------------------------------------ */
#faq .fine { margin-top: 28px; }
#faq .fine a { color: var(--ink-2); text-underline-offset: 3px; }
.closer-in {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: 48px 72px;
  align-items: start;
}
.closer .lead { margin: 20px 0 0; }
.closer .cta-row { margin-top: 32px; }
.closer .proof {
  margin-top: 0;
  padding-block: 4px 0;
  padding-inline: 48px 0;
  border-top: 0;
  border-inline-start: 1px solid var(--rule);
}
.closer .proof .fine { margin-top: 18px; }
.closer .proof .dial-inline { color: var(--ink-2); text-underline-offset: 3px; }
.closer-more { margin-top: 56px; }

@media (max-width: 900px) {
  .closer-in { grid-template-columns: 1fr; }
  .closer .proof { padding: 30px 0 0; border-inline-start: 0; border-top: 1px solid var(--rule); }
  .works-grid { grid-template-columns: 1fr; margin-top: 40px; }
  .works-grid > div { padding: 22px 0; border-bottom: 1px solid var(--rule-soft); }
  .routes > div,
  .stop-rows > div { grid-template-columns: 1fr; }
  .roi.roi-sentence-form { grid-template-columns: 1fr; }
  .roi-sentence { max-width: 30ch; }
}

/* ===========================================================================
   Apple look, 17 September 2026 (measured on apple.com; was Navy + Electric Blue).
   Everything below restyles the rules above; it comes last so it wins, and it
   repeats its own breakpoints for the same reason. White ground, near-black
   ink, one blue for fills, focus and links; the system stack (SF Pro on Apple
   devices, Inter elsewhere), 600 headlines, 17px body, 400 pill buttons.
   Rhythm comes from full-width bands: white sections with hairline-bordered
   18px tiles, one light grey band, one near-black band, and faint blue
   washes between some sections. Copy, order and generated markers untouched.
   =========================================================================== */

:root {
  --card-line: var(--bl-blue-line);
  --card-radius: var(--bl-radius-card);
  --band-pad: 104px;
  --site-shadow-fab: 0 14px 34px -14px rgba(0, 0, 0, 0.45);
  --site-shadow-fab-soft: 0 12px 28px -16px rgba(0, 0, 0, 0.35);
}

body { font-size: var(--bl-text-size); line-height: var(--bl-line-body); color: var(--bl-ink-900); }
p { color: var(--bl-text-2); }
/* Apple's body tracking, set where the text is so the em resolves at its own size. */
p,
.lead { letter-spacing: var(--bl-track-body); }
.wrap { max-width: 1200px; padding: 0 32px; }
section { padding: var(--band-pad) 0; }
.rule { border-top: 1px solid var(--bl-rule-soft); }

/* --- Type ------------------------------------------------------------------ */
.display {
  font-family: var(--bl-font-display);
  font-weight: var(--bl-weight-display);
  letter-spacing: var(--bl-track-h1);
  color: var(--bl-ink-900);
}
h1.display {
  font-size: clamp(2.55rem, 1.5rem + 4.2vw, 4.6rem);
  line-height: 1.07;
  letter-spacing: var(--bl-track-display);
}
h2.display {
  font-size: clamp(2rem, 1.35rem + 2.1vw, 3rem);
  font-weight: var(--bl-weight-display);
  line-height: 1.1;
  letter-spacing: var(--bl-track-h2);
}
.eyebrow {
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--bl-accent-text);
  margin-bottom: 18px;
}
.lead { font-size: 1.1875rem; line-height: 1.42; color: var(--bl-text-2); }
:focus-visible { outline: 2px solid var(--bl-blue); outline-offset: 2px; }

.sec-head { grid-template-columns: minmax(0, 1fr); gap: 16px; max-width: 780px; align-items: start; }
.sec-head .sec-lead { max-width: 60ch; }

/* (The header was repainted here. It is now defined once, under "Kopfzeile"
   at the top of this file, holding the values this block used to impose.) */

/* --- Buttons: Apple pills, 17px 400 --------------------------------------- */
.btn {
  padding: 11px 21px;
  font-size: 1.0625rem;
  font-weight: var(--bl-weight-button);
  background: var(--bl-blue);
  border-color: var(--bl-blue);
  color: var(--bl-white);
}
.btn:hover { background: var(--bl-blue-hover); border-color: var(--bl-blue-hover); color: var(--bl-white); }
.btn:active { background: var(--bl-blue-pressed); border-color: var(--bl-blue-pressed); }
.btn.line { background: var(--bl-ground); color: var(--bl-ink-900); border-color: var(--bl-rule-strong); }
.btn.line:hover { background: var(--bl-blue-tint); color: var(--bl-ink-900); border-color: var(--bl-blue); }

/* --- Cards: the one card language for every white section ------------------ */
#channels .channels-4 > li,
#works .works-grid > div,
.problem .problem-grid > div,
#price .plan,
.knows > div {
  background: var(--bl-ground);
  border: 1px solid var(--card-line);
  border-radius: var(--card-radius);
  padding: 28px 26px 30px;
}

/* --- Hero ------------------------------------------------------------------ */
/* No decorative dot grid above the headline: the owner asked for it gone. The
   hero opens straight on the headline and the example conversations. */
/* The headline starts high: the eyebrow sits a short step under the header,
   not a third of the way down the screen, and the copy is aligned to the top
   of the card beside it rather than centred against it. */
/* 96px from 22 Sep 2026: the founder wanted the headline and Belle a little
   lower, clear of the header. Desktop only; the phone rules below own theirs. */
.hero {
  padding: 96px 0 88px;
  background: linear-gradient(180deg, var(--bl-ground) 0%, var(--bl-ground) 62%, var(--bl-blue-tint) 100%);
}
.hero-demo { gap: 56px; }
/* The channel line, directly under the promise. Larger than the eyebrow it
   replaced and quieter than the headline: "Someone always answers" is the
   claim, and this is the sentence that says where. */
.hero-sub {
  font-size: clamp(1.25rem, 1.05rem + 0.8vw, 1.65rem);
  line-height: 1.25;
  font-weight: 500;
  color: var(--bl-ink-900);
  margin-top: 16px;
  max-width: 26ch;
  text-wrap: balance;
}
/* A wider measure was tried here on 7 Oct 2026 to make room for a fourth
   channel name and did nothing: at 375px the column is already narrower than
   26ch, so the max-width was never what was binding. The name came out of the
   line instead, and went back in on 8 October when the room was found
   elsewhere (`heroChannels`, and the 400px block further down, which sets this
   sentence one step smaller so four names still set two lines). */
.hero .lead { margin-top: 20px; max-width: 44ch; }
.hero .cta-row { margin-top: 32px; }
.hero-note { color: var(--bl-muted); font-size: 0.9rem; }

/* --- Talk to your next receptionist ------------------------------------- */
/* The chips answer the question that stops a visitor pressing anything at all:
   what do I even say to it. Quiet buttons, not a form. */
.ask { margin-top: 36px; max-width: 760px; }
.ask-who { display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px 12px; margin: 0 0 18px; }
.ask-name { font-family: var(--bl-font-display); font-weight: var(--bl-weight-heading); font-size: 1.15rem; color: var(--bl-ink-900); }
.ask-role { font-size: 0.9rem; color: var(--bl-text-2); }
.ask-chips { display: flex; flex-wrap: wrap; gap: 10px; }
.ask-chip {
  font: inherit;
  font-size: 0.95rem;
  padding: 10px 18px;
  border-radius: 999px;
  border: 1px solid var(--bl-rule-strong);
  background: var(--bl-ground);
  color: var(--bl-ink-900);
  cursor: pointer;
  text-align: start;
}
.ask-chip:hover { border-color: var(--bl-blue); background: var(--bl-blue-tint); }
/* No JavaScript, no chat to open: a button that cannot do anything is not shown. */
.ask-chips:empty { display: none; }
.ask-note { margin: 16px 0 0; font-size: 0.86rem; }

/* --- Trust strip ----------------------------------------------------------- */
/* A quiet row, not a band of cards: these are reasons to keep reading, not
   claims that each want a box. It sits on the tint the hero fades into, so it
   reads as the foot of the hero rather than the first section after it. */
.trust { padding: 0 0 34px; background: var(--bl-blue-tint); }
/* Pulled up into the hero's own bottom padding, which is sized for a hero that
   ends the screen. The strip is the foot of the hero, not the next thing after
   a gap — an adjacent selector rather than `:has`, so it needs nothing modern. */
.hero + .trust { margin-top: -46px; }
.trust-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 30px;
  margin: 0;
  padding: 22px 0 0;
  list-style: none;
  border-top: 1px solid var(--bl-rule-soft);
  color: var(--bl-text-2);
  font-size: 0.95rem;
  letter-spacing: var(--bl-track-body);
}
.trust-row > li { display: flex; align-items: baseline; gap: 9px; }
/* The dot is drawn, not typed: a character here would be read out. */
.trust-row > li::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--bl-accent-text);
  flex: none;
  transform: translateY(-2px);
}

.hero-demo {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
}
.hero-demo .cta-row { gap: 12px 14px; }
.mark-ground { fill: var(--mark-ground); }
.mark-glyph { fill: var(--mark-glyph); }

/* The hero picture: one card, one conversation at a time. The three
   conversations Belline has today and the calendar a request lands in are
   tabs of the same card (site.js), so the hero shows every channel by name
   without four boxes competing with the headline. Belle's face is the bubble
   in the corner, so the card leaves that corner free (below). Without
   JavaScript the four simply stack. */
.stage {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 16px;
  align-items: start;
  width: 380px;
  max-width: 100%;
}

.demo-card,
.stage .cal {
  margin: 0;
  min-width: 0;
  background: var(--bl-ground);
  border: 1px solid var(--card-line);
  border-radius: var(--card-radius);
  font-size: 0.86rem;
  line-height: 1.45;
  color: var(--bl-ink-900);
}
.demo-card { overflow: hidden; }

.demo-head {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 48px;
  padding: 9px 14px;
  background: var(--bl-ground);
  border-bottom: 1px solid var(--card-line);
}
.demo-badge svg { width: 26px; height: 26px; display: block; }
.demo-title { font-weight: 600; white-space: nowrap; color: var(--bl-ink-900); }
.demo-example { margin-inline-start: auto; font-size: 0.72rem; color: var(--bl-muted); white-space: nowrap; }
.demo-head-ink { background: var(--bl-navy); border-bottom-color: transparent; }
.demo-head-ink .demo-title { color: var(--bl-on-navy); }
.demo-head-ink .demo-example { color: var(--bl-on-navy-2); }
/* Die offizielle WhatsApp-Marke ist selbst schon ein Kreis (founder,
   23.09.2026): der getönte Kreis darunter fiele als Aufkleber auf einem Knopf
   auf. Also trägt die Marke die 26px allein, in ihren eigenen Farben. */
.demo-wa-icon {
  display: inline-grid;
  place-items: center;
  width: 26px;
  height: 26px;
  flex: none;
  border-radius: 50%;
  background: transparent;
}
.demo-wa-icon svg { width: 100%; height: 100%; display: block; }

/* Instagram's icon in the example head, the same size and shape as WhatsApp's
   beside it. The mark carries its own disc and gradient, so there is nothing
   to colour here — the same reason the round button in Belle's row stopped
   painting a background of its own. */
.demo-ig-icon {
  display: inline-grid;
  place-items: center;
  width: 26px;
  height: 26px;
  flex: none;
  border-radius: 50%;
  background: transparent;
}
.demo-ig-icon svg { width: 100%; height: 100%; display: block; }

/* The messages arrive on the same beat as WhatsApp's: four here rather than
   two, so the pair after them follows at the same spacing. */
.ig-thread .msg:nth-child(1) { animation-delay: 4.6s; }
.ig-thread .msg:nth-child(2) { animation-delay: 5.2s; }
.ig-thread .msg:nth-child(3) { animation-delay: 5.8s; }
.ig-thread .msg:nth-child(4) { animation-delay: 6.4s; }
.stage.is-tabbed .ig-thread .msg:nth-child(1) { animation-delay: 0.3s; }
.stage.is-tabbed .ig-thread .msg:nth-child(2) { animation-delay: 0.9s; }
.stage.is-tabbed .ig-thread .msg:nth-child(3) { animation-delay: 1.5s; }
.stage.is-tabbed .ig-thread .msg:nth-child(4) { animation-delay: 2.1s; }

.chat-thread {
  list-style: none;
  margin: 0;
  padding: 14px 12px 14px;
  display: grid;
  gap: 8px;
}
.msg { max-width: 92%; padding: 8px 12px; border-radius: 15px; }
.msg-visitor {
  justify-self: end;
  background: var(--bl-blue);
  color: var(--bl-white);
  border-end-end-radius: 5px;
}
.msg-belline {
  justify-self: start;
  background: var(--bl-surface);
  color: var(--bl-ink-900);
  border-end-start-radius: 5px;
}
.msg-source { display: block; margin-top: 5px; font-size: 0.72rem; color: var(--bl-muted); }

.call-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 2px 14px 12px;
  background: var(--bl-navy);
  color: var(--bl-on-navy);
}
.call-who { display: grid; gap: 1px; min-width: 0; }
.call-k { font-size: 0.72rem; color: var(--bl-on-navy-2); }
.call-num { font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.call-level { margin-inline-start: auto; display: inline-flex; align-items: center; gap: 3px; height: 20px; }
.call-level i { display: block; width: 3px; border-radius: 2px; background: var(--bl-blue-lit); }
.call-level i:nth-child(1) { height: 6px; }
.call-level i:nth-child(2) { height: 13px; }
.call-level i:nth-child(3) { height: 9px; }
.call-level i:nth-child(4) { height: 18px; }
.call-level i:nth-child(5) { height: 8px; }
.call-level i:nth-child(6) { height: 12px; }
.call-level i:nth-child(7) { height: 5px; }
.call-time { font-size: 0.82rem; font-variant-numeric: tabular-nums; }

.call-lines {
  list-style: none;
  margin: 0;
  padding: 14px 14px 10px;
  display: grid;
  gap: 9px;
  color: var(--bl-text-2);
}
.call-lines li:nth-child(even) { color: var(--bl-ink-900); padding-inline-start: 10px; border-inline-start: 2px solid var(--bl-blue); }
.call-said-k { display: block; font-size: 0.72rem; font-weight: 600; color: var(--bl-muted); }

.call-sent { margin: 2px 12px 12px; padding: 10px 12px; background: var(--bl-surface); border-radius: 10px; }
.call-sent-head {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 8px;
  padding: 3px 10px 3px 8px;
  max-width: none;
  border-radius: var(--bl-radius-pill);
  background: var(--bl-success-tint);
  color: var(--bl-success);
  font-size: 0.76rem;
  font-weight: 600;
}
.call-sent-head svg { width: 14px; height: 14px; }
.call-sent dl { margin: 0; display: grid; gap: 4px; }
.call-sent dl div { display: grid; grid-template-columns: 4.6em minmax(0, 1fr); gap: 8px; }
.call-sent dt { font-size: 0.75rem; color: var(--bl-muted); }
.call-sent dd { margin: 0; font-size: 0.8rem; color: var(--bl-ink-900); }

/* The calendar, and the dashed line that carries the call's request into it. */
.stage .cal { position: relative; }
.stage .cal::before {
  content: "";
  position: absolute;
  inset-inline-start: 34px;
  top: -19px;
  height: 18px;
  border-inline-start: 2px dashed var(--bl-blue);
  transform-origin: top;
}
.cal-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 12px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--card-line);
}
.cal-day { display: flex; align-items: baseline; gap: 8px; }
.cal-dow {
  font-family: var(--bl-font-display);
  font-weight: var(--bl-weight-heading);
  font-size: 1rem;
  letter-spacing: -0.015em;
  color: var(--bl-ink-900);
}
.cal-sub { font-size: 0.72rem; color: var(--bl-muted); }
.cal-soon { background: var(--bl-ground); }
/* The calendar's badge names every calendar that is live, and with all four
   it is 365px of text in English, 414 in German and 388 in Arabic. `.state`
   never wraps, so on a phone this one badge made the whole page 398–448px wide
   on a 390px screen and every page scrolled sideways (launch audit, 15 Oct
   2026, B4). It wraps instead, inside the card's width. */
.cal-head .state {
  max-width: 100%;
  height: auto;
  min-height: 26px;
  padding-block: 5px;
  line-height: 1.25;
  white-space: normal;
}

.cal-body {
  display: grid;
  grid-template-columns: 2.8rem minmax(0, 1fr);
  padding: 14px 12px 12px 8px;
}
.cal-hours {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-rows: repeat(4, 52px);
  font-size: 0.7rem;
  color: var(--bl-muted);
  font-variant-numeric: tabular-nums;
}
.cal-hours li { transform: translateY(-0.55em); }
.cal-events {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-rows: repeat(8, 26px);
  background: repeating-linear-gradient(180deg, var(--card-line) 0 1px, transparent 1px 52px);
}
.cal-ev {
  min-width: 0;
  margin: 3px 0 2px;
  padding: 4px 9px;
  overflow: hidden;
  border-radius: 7px;
  border-inline-start: 3px solid var(--bl-muted);
  background: var(--bl-surface);
  font-size: 0.76rem;
  line-height: 1.3;
  color: var(--bl-ink-900);
}
.cal-ev-a { grid-row: 1 / 3; }
.cal-ev-b { grid-row: 3 / 4; white-space: nowrap; text-overflow: ellipsis; padding-block: 2px; }
.cal-time { margin-inline-end: 6px; color: var(--bl-muted); font-variant-numeric: tabular-nums; }
.cal-what { display: block; color: var(--bl-muted); }
.cal-ev-new {
  grid-row: 5 / 8;
  display: grid;
  gap: 2px;
  align-content: start;
  padding: 6px 9px;
  background: var(--bl-blue-tint);
  border: 1.5px dashed var(--bl-blue);
}
.cal-new-k { font-size: 0.7rem; font-weight: 600; color: var(--bl-accent-text); }
.cal-new-what { font-weight: 600; }
.cal-new-state {
  justify-self: start;
  margin-top: 3px;
  padding: 2px 9px;
  border-radius: var(--bl-radius-pill);
  background: var(--bl-warning-tint);
  color: var(--bl-warning);
  font-size: 0.7rem;
  font-weight: 600;
}

/* The one orchestrated moment. The cards arrive, each conversation plays out
   once, the call's request travels down the dashed line and lands in the
   calendar as a request waiting for the team, and WhatsApp finishes last.
   Then everything rests. Reduced motion shows the finished state at once. */
@keyframes demo-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}
@keyframes demo-level {
  0%, 100% { transform: scaleY(1); }
  50% { transform: scaleY(0.35); }
}
@keyframes request-line {
  from { transform: scaleY(0); }
  to { transform: scaleY(1); }
}
@keyframes request-lands {
  from { opacity: 0; transform: translateY(-10px); }
  to { opacity: 1; transform: none; }
}
.stage .demo-card,
.stage .cal { animation: demo-in 0.55s cubic-bezier(0.2, 0.7, 0.2, 1) both; }
.stage .demo-call { animation-delay: 0.12s; }
.stage .cal { animation-delay: 0.24s; }
.stage .demo-wa { animation-delay: 0.36s; }
.chat-thread .msg,
.call-lines li,
.call-sent { animation: demo-in 0.42s cubic-bezier(0.2, 0.7, 0.2, 1) both; }
.demo-chat .msg:nth-child(1) { animation-delay: 0.5s; }
.demo-chat .msg:nth-child(2) { animation-delay: 1.1s; }
.demo-chat .msg:nth-child(3) { animation-delay: 1.9s; }
.demo-chat .msg:nth-child(4) { animation-delay: 2.5s; }
.call-lines li:nth-child(1) { animation-delay: 0.8s; }
.call-lines li:nth-child(2) { animation-delay: 1.4s; }
.call-lines li:nth-child(3) { animation-delay: 2s; }
.call-lines li:nth-child(4) { animation-delay: 2.6s; }
.call-sent { animation-delay: 3.1s; }
.stage .cal::before { animation: request-line 0.35s ease-out 3.5s both; }
.cal-ev-new { animation: request-lands 0.5s cubic-bezier(0.2, 0.7, 0.2, 1) 3.8s both; }
.cal-new-state { animation: demo-in 0.4s ease-out 4.3s both; }
.wa-thread .msg:nth-child(1) { animation-delay: 4.6s; }
.wa-thread .msg:nth-child(2) { animation-delay: 5.2s; }
/* The WhatsApp chatbot page's hero example (scripts/seo/render.ts): alone in
   the hero, so its messages arrive from the start rather than after the home
   page's chat and call have played. */
.hero-wa { width: 100%; max-width: 420px; justify-self: center; align-self: center; }
.hero-wa .wa-thread .msg:nth-child(1) { animation-delay: 0.4s; }
.hero-wa .wa-thread .msg:nth-child(2) { animation-delay: 1s; }
.hero-wa .wa-thread .msg:nth-child(3) { animation-delay: 1.8s; }
.hero-wa .wa-thread .msg:nth-child(4) { animation-delay: 2.4s; }
.call-level i { animation: demo-level 0.6s ease-in-out 0.6s 4; transform-origin: center; }
.call-level i:nth-child(2n) { animation-delay: 0.75s; }
.call-level i:nth-child(3n) { animation-delay: 0.9s; }
@media (prefers-reduced-motion: reduce) {
  .stage .demo-card,
  .stage .cal,
  .stage .cal::before,
  .chat-thread .msg,
  .call-lines li,
  .call-sent,
  .cal-ev-new,
  .cal-new-state,
  .call-level i { animation: none; }
}

/* --- The card's tabs ----------------------------------------------------------
   A segmented control on the card's top edge, and only the chosen panel under
   it, at its own height (no empty space under a short conversation; beside
   the taller headline column nothing on the page moves). Each panel's own
   messages play again when it is chosen (unless motion is reduced), with
   delays for one panel, not for four in a row. */
.stage.is-tabbed {
  gap: 0;
  padding: 8px;
  background: var(--bl-ground);
  border: 1px solid var(--card-line);
  border-radius: calc(var(--card-radius) + 6px);
  box-shadow: 0 24px 48px -32px rgba(29, 29, 31, 0.28);
}
.stage-tabs {
  display: flex;
  gap: 2px;
  padding: 3px;
  margin: 0 0 8px;
  border-radius: var(--bl-radius-pill);
  background: var(--bl-surface);
}
.stage-tab {
  flex: 1 1 0;
  min-width: 0;
  min-height: 40px;
  padding: 0 8px;
  border: 0;
  border-radius: var(--bl-radius-pill);
  background: transparent;
  color: var(--bl-text-2);
  font: inherit;
  font-size: 0.84rem;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.stage-tab:hover { color: var(--bl-ink-900); }
.stage-tab[aria-selected="true"] {
  background: var(--bl-ground);
  color: var(--bl-ink-900);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 0 0.5px rgba(0, 0, 0, 0.06);
}
.stage-tab:focus-visible { outline: 2px solid var(--bl-blue); outline-offset: 2px; }
.stage.is-tabbed > figure {
  border: 0;
  border-radius: var(--card-radius);
  animation: none;
}
.stage.is-tabbed > figure:not(.is-on) { display: none; }
.stage.is-tabbed .cal::before { display: none; }
.stage.is-tabbed .demo-head { border-bottom-color: var(--bl-rule-soft); }
.stage.is-tabbed .cal-ev-new { animation-delay: 0.5s; }
.stage.is-tabbed .cal-new-state { animation-delay: 1s; }
.stage.is-tabbed .wa-thread .msg:nth-child(1) { animation-delay: 0.3s; }
.stage.is-tabbed .wa-thread .msg:nth-child(2) { animation-delay: 0.9s; }
@media (prefers-reduced-motion: reduce) {
  .stage-tab { transition: none; }
}

/* The hero's demonstration sits in its own column now (Belle on video), so
   nothing has to leave room for a floating bubble at rest. */
@media (min-width: 1101px) {
  .hero-demo { gap: 56px; }
  .hero-demo h1.display { font-size: clamp(2.55rem, 1rem + 4vw, 4.6rem); }
}
/* With Belle in the hero, her column shares the width instead of hugging the
   far edge, so the bubble (centred in it) sits nearer the words. */
@media (min-width: 901px) {
  .hero-demo.has-video-hero { grid-template-columns: minmax(0, 1fr) minmax(340px, 0.85fr); }
}
@media (max-width: 900px) {
  .hero-demo { grid-template-columns: minmax(0, 1fr); gap: 40px; }
}

/* Three plain facts as a light strip, no numbers. */
.plain-facts {
  margin-top: 72px;
  border-top: 0;
  background: var(--bl-ground);
  border: 1px solid var(--card-line);
  border-radius: var(--card-radius);
  padding: 8px 0;
}
.plain-facts li,
.plain-facts li:first-child,
.plain-facts li:last-child {
  padding: 22px 28px;
  border-inline-end: 1px solid var(--card-line);
  color: var(--bl-text-2);
  font-size: 0.95rem;
}
.plain-facts li:last-child { border-inline-end: 0; }
.plain-facts strong {
  font-family: var(--bl-font-display);
  font-size: 1.1rem;
  font-weight: var(--bl-weight-heading);
  letter-spacing: -0.015em;
  color: var(--bl-ink-900);
}

/* --- Small headings in cards ----------------------------------------------- */
.problem-grid h3,
.works h3,
.channels h3,
.steps-home h3,
.knows h3,
.plan h3,
.proof h3,
#channels .channels-4 h3 {
  font-family: var(--bl-font-display);
  font-weight: var(--bl-weight-heading);
  font-size: 1.15rem;
  line-height: 1.3;
  letter-spacing: -0.015em;
  color: var(--bl-ink-900);
}

/* --- The problem ----------------------------------------------------------- */
.problem { border-top: 0; }
.problem .problem-h { font-size: clamp(2rem, 1.3rem + 2.4vw, 3.2rem); max-width: 22ch; }
.problem .problem-grid { gap: 20px; border-top: 0; margin-top: 48px; }
.problem-grid p { font-size: 0.98rem; }
.problem-coda {
  font-family: var(--bl-font-display);
  font-weight: var(--bl-weight-display);
  letter-spacing: -0.025em;
  color: var(--bl-ink-900);
}

/* --- Where Belline answers ------------------------------------------------- */
#channels { background: linear-gradient(180deg, var(--bl-blue-tint) 0%, var(--bl-ground) 240px); border-top: 0; }
#channels .channels-4 { gap: 20px; border-top: 0; margin-top: 48px; }
#channels .channels-4 > li:hover { border-color: var(--bl-border-hover); }
/*
  Four marks, not four glyphs on tiles.

  These were line drawings in a pale rounded tile, with 9px of padding holding
  them off its edges — except WhatsApp, which was already its own brand circle
  and sat in the tile looking like a sticker on a card. On 6 Oct 2026 the other
  three became marks too: the blue chat button, the ink phone button and Belle's
  own bubble, because "for chat and voice use our vlue chatbot button and for
  your phone our black phone button, both same as you did for whatsapp"
  (founder).

  With nothing left that needs a ground to sit on, the tile and the padding go.
  Each mark is the 44px circle, drawn as the button it stands for, which is also
  what made the glyphs sit in the upper-left of their own circles: a 48 viewBox
  squeezed into a 26px content box inside a 44px border box.
*/
#channels .ico {
  width: 44px;
  height: 44px;
  padding: 0;
  margin-bottom: 20px;
  border-radius: 50%;
  background: none;
  /* The marks carry their own colours; nothing here strokes them. */
  stroke: none;
  color: var(--bl-blue);
}
/*
  Belle's own bubble, where the video card used to carry a camera (founder,
  6 Oct 2026: "instead of the camera icon use belles bubble"). Her face in the
  blue ring — the thing a visitor meets in the corner of this page — rather
  than a drawing of the medium.

  No tile and no padding: the other three are glyphs that need a ground to sit
  on, and this is a photograph, which is its own. It keeps the 44px box so the
  four line up.

  A background image on a span, not an `<image>` inside the inline SVG, and the
  reason is the flag system rather than taste. The card is a `video.avatar`
  swap (src/lib/site-flags.ts), the build fingerprints asset filenames, and a
  swap carrying `/video/faces/<id>.jpg` would be written into the page with a
  path the build does not use — worse, the reverse swap could never find its
  needle in a built page, so serving the flag-on build with video off would
  leave the card in. check:webchat caught exactly that. The URL belongs in this
  file, where the build rewrites it like every other asset, and the swap
  carries a class name that nothing hashes.
*/
#channels .ico-belle {
  display: block;
  padding: 0;
  border-radius: 50%;
  background: var(--bl-blue-tint) url("/video/faces/rf90eb925bd8.1cbc7918.jpg") center 22% / cover no-repeat;
  box-shadow: inset 0 0 0 2px var(--bl-blue);
}
#channels .channels-4 p { font-size: 0.94rem; }
#channels .channel-how { color: var(--bl-accent-text); font-weight: 500; }

/* The eight faces (src/lib/site-flags.ts, video.faces).
   A row rather than a grid, deliberately: a grid of eight reads as a complete
   set to be studied, and a row reads as examples — which is what they are,
   under a sentence that has already said how many there are. */
#channels .faces { margin-top: 36px; }
#channels .faces-lead { margin: 0 0 14px; color: var(--bl-text-2); font-size: 0.94rem; }
/* 16px of gap, not 12: the ring adds 4px on every side, and at the old gap
   the circles touched. */
#channels .faces-row { display: flex; flex-wrap: wrap; gap: 16px; margin: 4px 0 0; padding: 0; list-style: none; }
/* The head sits in the middle of the circle because the still is cut that
   way when it is built (scripts/build-face-stills.ts), not because the page
   zooms into it. A CSS crop here centred the head by taking the forehead off:
   the picture has to be right before it is a circle. */
#channels .faces-row li {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  overflow: hidden;
  /* The same blue ring the bubble wears in the corner of a customer's website
     (founder, f13: "it might look nicer to add the blue circle around them").
     White first, then blue, so the ring reads against the photograph as well
     as against the page — the same two-step the video bubble draws. */
  box-shadow: 0 0 0 2px var(--bl-ground), 0 0 0 4px var(--bl-blue);
  /* Held until the photograph loads, so a slow connection sees the row shape
     rather than eight gaps. */
  background: var(--bl-surface);
}
#channels .faces-row img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
@media (max-width: 560px) {
  #channels .faces-row li { width: 56px; height: 56px; }
}
#channels .channels-4 .channel-how a { color: var(--bl-accent-text); }
.state-soon { color: var(--bl-muted); border-color: var(--bl-rule-strong); }

/* --- Works with how you already work --------------------------------------- */
#works .works-grid { gap: 20px; border-top: 0; margin-top: 48px; }
#works .works-grid p { font-size: 0.96rem; }
.works .routes-h { margin-top: 56px; font-family: var(--bl-font-display); font-weight: var(--bl-weight-heading); font-size: 1.15rem; letter-spacing: -0.015em; }
.routes {
  border: 1px solid var(--card-line);
  border-radius: var(--card-radius);
  padding: 4px 28px;
  background: var(--bl-ground);
}
.routes > div { border-bottom: 1px solid var(--card-line); padding: 20px 0; }
.routes > div:last-child { border-bottom: 0; }
.routes dt { font-family: var(--bl-font-display); font-weight: var(--bl-weight-heading); font-size: 1.02rem; letter-spacing: -0.01em; }
.routes dd { color: var(--bl-text-2); }

/* --- It knows when to stop: the dark navy band ----------------------------- */
#stop { background: var(--bl-navy); border-top: 0; color: var(--bl-on-navy); }
#stop .display { color: var(--bl-on-navy); }
#stop .lead,
#stop p { color: var(--bl-on-navy-2); }
#stop .stop-rows {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
  margin-top: 48px;
  border-top: 0;
}
#stop .stop-rows > div {
  display: block;
  padding: 26px 24px 28px;
  background: var(--bl-navy-card);
  border: 1px solid var(--bl-navy-line);
  border-radius: var(--card-radius);
}
#stop .stop-rows h3 {
  margin: 0 0 10px;
  font-family: var(--bl-font-display);
  font-weight: var(--bl-weight-heading);
  font-size: 1.1rem;
  line-height: 1.35;
  letter-spacing: -0.015em;
  color: var(--bl-on-navy);
}
#stop .stop-rows p { font-size: 0.95rem; }
#stop .stop-small { margin-top: 24px; }
#stop .cta-aside { color: var(--bl-on-navy-2); }
#stop .btn.line { background: transparent; color: var(--bl-white); border-color: rgba(255, 255, 255, 0.45); }
#stop .btn.line:hover { background: var(--bl-white); color: var(--bl-ink-900); border-color: var(--bl-white); }
#stop :focus-visible { outline-color: var(--bl-focus-on-dark); }
#stop + section { border-top: 0; }

/* --- Who it is for: example kinds of business, not links ------------------ */
#for .kinds {
  list-style: none;
  margin: 40px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 12px;
  max-width: 1000px;
}
#for .kinds li {
  padding: 10px 18px;
  background: var(--bl-ground);
  border: 1px solid var(--card-line);
  border-radius: var(--bl-radius-pill);
  font-family: var(--bl-font-display);
  font-weight: var(--bl-weight-heading);
  font-size: 1rem;
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--bl-ink-900);
}
#for .kinds-note { margin: 28px 0 0; max-width: 62ch; font-size: 0.95rem; color: var(--bl-text-2); }
#for .kinds-note a { color: var(--bl-accent-text); text-underline-offset: 3px; }

/* --- Set up from what you already have: the light grey band ---------------- */
#how { background: var(--bl-surface); border-top: 0; }
#how .steps-home { gap: 20px; margin-top: 48px; }
#how .step {
  background: var(--bl-ground);
  border: 1px solid var(--card-line);
  border-radius: var(--card-radius);
  padding: 28px 26px 30px;
}
#how .steps-home .num {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  margin-bottom: 20px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: var(--bl-blue-tint);
  color: var(--bl-accent-text);
  font-family: var(--bl-font-display);
  font-size: 1.05rem;
  font-weight: var(--bl-weight-heading);
}
#how .step p { color: var(--bl-text-2); }
#how + section { border-top: 0; }

/* --- The calculator -------------------------------------------------------- */
#worth .roi.roi-sentence-form { border-top: 0; padding-top: 0; margin-top: 48px; align-items: center; }
.roi-sentence {
  font-family: var(--bl-font-display);
  font-weight: var(--bl-weight-display);
  letter-spacing: -0.025em;
  color: var(--bl-ink-900);
}
.roi-field input {
  color: var(--bl-ink-900);
  border: 1px solid var(--bl-rule-strong);
  border-radius: var(--bl-radius-input);
  background: var(--bl-ground);
}
.roi-field input:focus-visible,
.roi-pick select:focus-visible { outline: 2px solid var(--bl-blue); outline-offset: 2px; border-color: var(--bl-blue); }
.roi-result {
  background: var(--bl-blue-tint);
  border: 1px solid var(--card-line);
  border-radius: var(--card-radius);
  padding: 30px 28px;
}
.roi-sentence-form .roi-out {
  font-family: var(--bl-font-display);
  font-weight: var(--bl-weight-display);
  font-size: clamp(2rem, 1.3rem + 2vw, 3.1rem);
  line-height: 1.08;
  letter-spacing: var(--bl-track-h1);
  color: var(--bl-ink-900);
}
.roi-detail,
.roi-pick { color: var(--bl-text-2); }
.roi-pick select { border-color: var(--bl-rule-strong); color: var(--bl-ink-900); }

/* --- Pricing: generated cards, styled here only ---------------------------- */
#price .cycle { border-color: var(--card-line); }
#price .cycle-opt { color: var(--bl-text-2); }
#price .cycle-opt.is-on { background: var(--bl-ink-900); color: var(--bl-white); }
#price .cycle-save { color: var(--bl-accent-text); letter-spacing: 0; text-transform: none; font-size: 0.8rem; font-weight: 600; }
#price .cycle-opt.is-on .cycle-save { color: var(--bl-blue-lit); }
/* Four cards since 2026-09-23 (the WhatsApp Receptionist). The count is not
   hard-coded: auto-fit keeps three abreast on a narrower desktop and four on a
   wide one, and the media queries below still take it to one column. */
#price .plans { gap: 20px; border-top: 0; margin-top: 40px; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
#price .plan { padding: 30px 28px 32px; }
#price .plan.is-best { border-color: var(--bl-blue); box-shadow: inset 0 0 0 1px var(--bl-blue); }
#price .plan-tag {
  align-self: start;
  justify-self: start;
  font-size: 0.8rem;
  letter-spacing: 0;
  text-transform: none;
  color: var(--bl-accent-text);
}
#price .plan.is-best .plan-tag {
  display: inline-flex;
  align-items: center;
  padding: 2px 12px;
  border-radius: 999px;
  background: var(--bl-blue-tint);
}
#price .plan h3 { font-size: 1.35rem; }
#price .plan-sub { color: var(--bl-muted); }
#price .plan-price .amt {
  font-family: var(--bl-font-display);
  font-weight: var(--bl-weight-display);
  letter-spacing: -0.035em;
  color: var(--bl-ink-900);
}
#price .plan-price .per,
#price .plan-price .billed { color: var(--bl-muted); }
#price .plan li { color: var(--bl-text-2); }
#price .plan li::before { width: 7px; height: 7px; top: 0.5em; border-radius: 999px; background: var(--bl-blue); }
#price .compare { font-family: var(--bl-font-display); font-weight: var(--bl-weight-display); letter-spacing: -0.025em; color: var(--bl-ink-900); }
#price .terms { border-top: 1px solid var(--card-line); gap: 28px; }
#price .terms h4 { font-family: var(--bl-font-display); font-weight: var(--bl-weight-heading); font-size: 0.95rem; color: var(--bl-ink-900); }
#price .terms p { color: var(--bl-muted); }

/* --- FAQ: a centred accordion on native details ---------------------------- */
#faq .wrap > .display { text-align: center; margin-inline: auto; }
#faq .faq { max-width: 780px; margin: 44px auto 0; border-top: 1px solid var(--card-line); }
#faq .faq details { border-bottom: 1px solid var(--card-line); }
#faq .faq summary {
  padding: 22px 4px;
  align-items: center;
  font-family: var(--bl-font-display);
  font-weight: var(--bl-weight-heading);
  font-size: 1.05rem;
  line-height: 1.4;
  letter-spacing: -0.01em;
  color: var(--bl-ink-900);
}
#faq .faq summary:hover { color: var(--bl-accent-text); }
#faq .faq summary::after {
  content: "";
  flex: none;
  width: 10px;
  height: 10px;
  margin-inline-end: 4px;
  border-inline-end: 2px solid var(--bl-blue);
  border-bottom: 2px solid var(--bl-blue);
  transform: translateY(-3px) rotate(45deg);
  transition: transform 0.18s ease;
}
#faq .faq details[open] summary::after { content: ""; transform: translateY(2px) rotate(225deg); }
#faq .faq .answer { padding: 0 4px 24px; }
#faq .faq .answer p { color: var(--bl-text-2); font-size: 0.98rem; }
#faq .fine { text-align: center; max-width: none; color: var(--bl-muted); }
#faq .fine a { color: var(--bl-accent-text); }

/* --- Closer: a blue wash --------------------------------------------------- */
#book { background: linear-gradient(180deg, var(--bl-ground) 0%, var(--bl-blue-tint) 100%); border-top: 0; }
#book .closer-in { align-items: center; }
#book .proof {
  padding: 30px 30px 32px;
  background: var(--bl-ground);
  border: 1px solid var(--card-line);
  border-inline-start: 1px solid var(--card-line);
  border-radius: var(--card-radius);
}
#book .proof ul li { color: var(--bl-text-2); }
#book .proof ul li::before { width: 6px; height: 6px; top: 0.55em; border-radius: 999px; background: var(--bl-blue); }
#book .fine,
#book .proof .fine { color: var(--bl-muted); }
#book .fine a,
#book .proof .dial-inline { color: var(--bl-accent-text); }

/* --- Footer ---------------------------------------------------------------- */
footer { background: var(--bl-ground); border-top: 1px solid var(--card-line); }
footer p { color: var(--bl-muted); }
footer a { color: var(--bl-ink-900); }

/* The three floating buttons used to be repainted here, a second time, 2,200
   lines below where they are built — and that is where the WhatsApp pill lost
   its green. They are defined exactly once now, under "The floating buttons"
   further up; nothing below that section may set their colour again. */
.chat-dock,
.call-dock { border-color: var(--card-line); border-radius: var(--card-radius); }

/* --- Trade pages and legal pages: same bands and cards --------------------- */
.knows { gap: 20px; border-top: 0; }
.knows p { color: var(--bl-text-2); }
.closer:not(#book) { background: linear-gradient(180deg, var(--bl-ground) 0%, var(--bl-blue-tint) 100%); }
.call { border-top: 1px solid var(--card-line); }
.call-tab[aria-selected="true"],
.call-status { color: var(--bl-accent-text); }
.call-tab[aria-selected="true"] { border-bottom-color: var(--bl-blue); }
/* Sentence case, like the homepage: the trade pages' tabs and call labels
   were still small uppercase with wide tracking. */
.call-tab,
.call-status,
.call-body .who,
.call-out .tag { text-transform: none; letter-spacing: 0; }
.call-tab { font-size: 0.9rem; font-weight: 600; }
.call-status { font-size: 0.82rem; font-weight: 600; }
.call-body .who { font-size: 0.8rem; font-weight: 600; }
.call-out .tag { font-size: 0.78rem; font-weight: 600; }
.call-listen:disabled { opacity: 0.5; cursor: default; }
.call-listen:disabled:hover { border-color: var(--rule); color: var(--ink-2); }
.call-body .agent { border-inline-start-color: var(--bl-blue); }
.call-out .tag { color: var(--bl-accent-text); border-color: var(--card-line); }
.terms { border-top-color: var(--card-line); }
.legal .display { font-weight: var(--bl-weight-display); }
.legal h2 { font-family: var(--bl-font-display); font-weight: var(--bl-weight-heading); letter-spacing: -0.015em; }
.legal a { color: var(--bl-accent-text); }
/* A button inside an article is still a button: the link colour above made
   the guides' "Get started" and /partners' "Apply by email" blue on blue. */
.legal a.btn, .legal a.btn:hover { color: var(--bl-white); }

@media (max-width: 1100px) {
  #channels .channels-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #channels .channels-4 > li,
  #channels .channels-4 > li:first-child,
  #channels .channels-4 > li:last-child,
  #channels .channels-4 > li:nth-child(2n),
  #channels .channels-4 > li:nth-child(2n + 1) { padding: 26px 24px 28px; border: 1px solid var(--card-line); }
}
@media (max-width: 1000px) {
  #price .plans { grid-template-columns: minmax(0, 1fr); }
  #price .plan,
  #price .plan:first-child,
  #price .plan:last-child { padding: 28px 24px 30px; border: 1px solid var(--card-line); }
  #price .plan.is-best { border-color: var(--bl-blue); }
  #stop .stop-rows { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  :root { --band-pad: 68px; }
  .wrap { padding: 0 20px; }
  body { font-size: var(--bl-text-size); }
  .hero { padding: 20px 0 64px; }
  /* On a phone the two buttons come straight under the headline, before the
     paragraph: they stay above Belle's bubble in the corner on a short screen
     (375x667), and they are what the headline is asking the visitor to do. */
  .hero-copy { display: flex; flex-direction: column; align-items: flex-start; }
  .hero .cta-row { order: 1; margin-top: 24px; }
  .hero .lead { order: 2; margin-top: 24px; }
  .hero-note { order: 3; }
  /* (The header bar and the phone menu are each defined once, in the
     max-width: 900px block under "Das Menü auf dem Telefon" near the top of
     this file — including the bar's own `padding-block`, the fix that used to
     be restated down here. The `.wrap` rule five lines up still sets the
     `padding` shorthand, so the bar's padding has to be written with
     `.top .top-in` to outrank it; it is, up there.) */
  .closer-in { gap: 32px; }
  #book .proof { padding: 26px 22px 28px; border-top: 1px solid var(--card-line); }
  #works .works-grid > div { padding: 24px 22px 26px; border-bottom: 1px solid var(--card-line); }
  .knows > div { padding: 24px 22px 26px; border-bottom: 1px solid var(--card-line); }
}
@media (max-width: 760px) {
  /* This was 0, because the header above supplied the air instead: `.top
     .top-in` had 12px of padding-block, and its bottom half stood in for this
     padding — a 24-for-24 swap, and it had to be a swap, because at 375x667
     the hero fits the first screen with about 2px to spare
     (tests-video/site-review.spec.ts measures it) and 24px added above has to
     come off somewhere below. The 24px comes back under Belle, so only the
     block above her moves.

     Then the header's padding-block went to 5px, and nothing put the missing
     air back. Measured on belline.ai 5 Oct 2026 at 754px wide: the headline
     started at y=43 with the sticky header's bottom edge at y=57, so "Someone
     always answers" was sitting *behind* the bar. That is the complaint the
     founder made three times.

     14px, which is exactly what the header gave up (7px off each side), so the
     first screen is no tighter than it was when the measurement above last
     passed. The bar's bottom edge is y=57 and the headline now starts there
     rather than under it. */
  .hero { padding-top: 14px; }
  /* Written with the same selector the phone hero layout uses further down,
     because `.hero-video { margin: 0 }` is a shorthand later in the file and a
     bare `.hero-video { margin-bottom }` here loses to it — the same way the
     header lost its padding to `.wrap`. */
  .hero-demo.has-video-hero .hero-video { margin-bottom: 24px; }
  .plain-facts { margin-top: 48px; padding: 0 22px; }
  .plain-facts li,
  .plain-facts li:first-child,
  .plain-facts li:last-child { padding: 20px 0; border-inline-end: 0; border-bottom: 1px solid var(--card-line); }
  .plain-facts li:last-child { border-bottom: 0; }
  #channels .channels-4 { grid-template-columns: minmax(0, 1fr); gap: 14px; }
  #stop .stop-rows { grid-template-columns: minmax(0, 1fr); gap: 14px; }
  .routes { padding: 4px 20px; }
}
@media (max-width: 600px) {
  #for .kinds { gap: 8px; margin-top: 32px; }
  #for .kinds li { padding: 8px 14px; font-size: 0.92rem; }
  #faq .faq summary { font-size: 1rem; }
}
@media (prefers-reduced-motion: reduce) {
  #faq .faq summary::after { transition: none; }
}

/* --- Integrations strip ------------------------------------------------------
   Directly under the hero. Six text wordmarks in the site's own display face,
   one size and weight, in muted grey that goes to full ink on hover, each with
   its state in words (the tags come from the flags; scripts/site-integrations.ts).
   No logo files: official marks may replace the wordmarks only once a
   partnership or that company's brand guidelines permit it.
   Contrast (tokens.css): muted 5.07 on white, 4.67 on the blue tint the band
   fades from; ink 16.83 / 15.48. Nothing moves on its own: no marquee, no
   auto-scroll, and the hover colour change is dropped under reduced motion. */
.connects {
  padding: 16px 0 32px; /* the hero above and the next band below bring their own space */
  border-top: 0;
  background: linear-gradient(180deg, var(--bl-blue-tint) 0%, var(--bl-ground) 100%);
}
.connects-h {
  margin: 0 0 22px;
  font-family: var(--bl-font-display);
  font-size: 1.15rem;
  font-weight: var(--bl-weight-heading);
  line-height: 1.3;
  letter-spacing: -0.015em;
  color: var(--bl-ink-900);
}
.connects-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  border-top: 1px solid var(--bl-rule);
  border-bottom: 1px solid var(--bl-rule);
}
.connect {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  min-width: 0;
  padding: 22px 18px 24px;
  border-inline-start: 1px solid var(--bl-rule-soft);
}
.connect:first-child { padding-inline-start: 0; border-inline-start: 0; }
.connect-logo { display: block; width: 40px; height: 40px; border-radius: 10px; object-fit: contain; }
.connect-name {
  font-family: var(--bl-font-display);
  font-size: 1.125rem;
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.015em;
  color: var(--bl-muted);
  overflow-wrap: anywhere;
  transition: color 0.18s ease;
}
@media (hover: hover) {
  .connect:hover .connect-name { color: var(--bl-ink-900); }
}
.connect .state { height: 24px; padding: 0 10px; background: transparent; }
.connect .state-available { background: var(--bl-success-tint); }
/* How the connection is made, when it is not that company's own API: shown
   under the tag so "Available" is never read on its own (Fresha, through the
   salon's own Google Calendar). Quiet, never hidden. */
.connect-via {
  margin-top: -4px;
  font-size: 0.82rem;
  line-height: 1.3;
  color: var(--bl-text-2);
  overflow-wrap: anywhere;
}
.state-roadmap { border-color: var(--bl-rule-strong); border-style: dashed; color: var(--bl-muted); font-weight: 500; }
.connects-ask { margin: 20px 0 0; font-size: 0.95rem; color: var(--bl-text-2); }
.connects-ask a { color: var(--bl-accent-text); text-underline-offset: 3px; white-space: nowrap; }

@media (max-width: 1000px) {
  .connects-list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .connect,
  .connect:first-child { padding: 20px 16px 22px; border-inline-start: 1px solid var(--bl-rule-soft); }
  .connect:nth-child(3n + 1) { padding-inline-start: 0; border-inline-start: 0; }
  .connect:nth-child(-n + 3) { border-bottom: 1px solid var(--bl-rule-soft); }
}
@media (max-width: 600px) {
  .connects { padding: 8px 0 24px; }
  .connects-h { font-size: 1.05rem; margin-bottom: 16px; }
  .connects-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .connect,
  .connect:first-child,
  .connect:nth-child(3n + 1) { padding: 18px 12px 20px 14px; border-inline-start: 1px solid var(--bl-rule-soft); border-bottom: 0; }
  .connect:nth-child(2n + 1) { padding-inline-start: 0; border-inline-start: 0; }
  .connect:nth-child(-n + 4) { border-bottom: 1px solid var(--bl-rule-soft); }
  .connect-name { font-size: 1rem; }
}
@media (prefers-reduced-motion: reduce) {
  .connect-name { transition: none; }
}

/* The moving strip. site.js adds .is-moving, wraps the list in a rail and a
   track, and appends a hidden copy so the loop has no seam. Without it (no
   JavaScript, or reduced motion) the list above stays still. */
.connects-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; }
.connects-pause {
  flex: none;
  margin: 0 0 22px;
  padding: 4px 12px;
  border: 1px solid var(--bl-rule-strong);
  border-radius: 999px;
  background: transparent;
  color: var(--bl-text-2);
  font: inherit;
  font-size: 0.85rem;
  cursor: pointer;
}
.connects-pause:hover { color: var(--bl-ink-900); border-color: var(--bl-ink-900); }
.connects-pause:focus-visible { outline: 2px solid var(--bl-accent-text); outline-offset: 2px; }
.connects.is-moving .connects-rail {
  overflow: hidden;
  border-top: 1px solid var(--bl-rule);
  border-bottom: 1px solid var(--bl-rule);
  -webkit-mask-image: linear-gradient(90deg, transparent 0, var(--bl-black) 6%, var(--bl-black) 94%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, var(--bl-black) 6%, var(--bl-black) 94%, transparent 100%);
}
.connects.is-moving .connects-track {
  display: flex;
  width: max-content;
  animation: connects-slide var(--connects-duration, 60s) linear infinite;
}
.connects.is-moving .connects-rail:hover .connects-track,
.connects.is-moving.is-paused .connects-track { animation-play-state: paused; }
.connects.is-moving .connects-list {
  display: flex;
  flex: none;
  border: 0;
}
.connects.is-moving .connect,
.connects.is-moving .connect:first-child,
.connects.is-moving .connect:nth-child(n) {
  width: 200px;
  flex: none;
  padding: 22px 20px 24px;
  border: 0;
  border-inline-start: 1px solid var(--bl-rule-soft);
}
@keyframes connects-slide {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (max-width: 600px) {
  .connects.is-moving .connect,
  .connects.is-moving .connect:first-child,
  .connects.is-moving .connect:nth-child(n) { width: 160px; padding: 18px 14px 20px; }
}

/* --- Land und Sprache ------------------------------------------------------
   Der Wähler im Kopf, vor "Get started" (scripts/site-locale.ts).
   Im Markup ein <details>: ohne JavaScript klappt er auf, und jedes Land ist
   ein Link. site.js macht daraus einen Knopf mit aria-expanded. Links die
   Länder mit ihrer Währung, rechts nur die Sprachen, die es für dieses Land
   gibt; die übrigen grau und ohne Link. Auf dem Telefon steht er im Menü in
   voller Breite, und das Panel liegt im Fluss statt darüber. */
@media (min-width: 901px) {
  .top nav a { white-space: nowrap; }
}
.locale { position: relative; }
.locale > summary { list-style: none; }
.locale > summary::-webkit-details-marker { display: none; }
.locale-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 38px;
  padding: 0 13px;
  border: 1px solid var(--bl-rule-strong);
  border-radius: var(--bl-radius-pill);
  background: transparent;
  color: var(--bl-text-2);
  font: inherit;
  font-size: 0.88rem;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
}
.locale-btn:hover { color: var(--bl-ink-900); border-color: var(--bl-ink-900); }
.locale-btn:focus-visible { outline: 2px solid var(--bl-blue); outline-offset: 2px; }
.locale-flag { width: 20px; height: 14px; flex: none; border-radius: 2px; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.09); }
.locale-chev { width: 10px; height: 10px; flex: none; transition: transform 0.2s ease; }
.locale[open] .locale-chev,
.locale.is-open .locale-chev { transform: rotate(180deg); }
.locale-panel {
  display: none;
  position: absolute;
  inset-inline-end: 0;
  top: calc(100% + 10px);
  z-index: 40;
  width: 530px;
  padding: 18px;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: 18px;
  background: var(--bl-ground);
  border: 1px solid var(--bl-rule);
  border-radius: var(--bl-radius-card);
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.12);
}
.locale[open] > .locale-panel,
.locale.is-open > .locale-panel { display: grid; }
/* Eleven countries since the English pages (13 Oct 2026): on a short laptop
   screen the list scrolls inside the panel rather than off the page. */
@media (min-width: 901px) {
  .locale-panel { max-height: calc(100vh - 110px); overflow-y: auto; }
}

/* Der Hinweis auf die Länderseite (site.js "a country page suggestion"):
   eine ruhige Zeile unter dem Kopf, ein Link und ein Schliessen-Knopf. */
.locale-hint {
  background: var(--bl-blue-tint);
  border-bottom: 1px solid var(--bl-rule);
  font-size: 0.92rem;
  color: var(--bl-ink-900);
}
.locale-hint-in { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 44px; padding-top: 6px; padding-bottom: 6px; }
.locale-hint p { margin: 0; }
.locale-hint a { color: var(--bl-blue); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }
.locale-hint-x {
  flex: none;
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--bl-muted);
  font: inherit;
  font-size: 1.3rem;
  line-height: 1;
  cursor: pointer;
}
.locale-hint-x:hover { color: var(--bl-ink-900); background: var(--bl-surface); }
.locale-hint-x:focus-visible { outline: 2px solid var(--bl-blue); outline-offset: 2px; }
.locale-panel[hidden] { display: none !important; }
.locale-h {
  margin: 0 0 8px;
  padding: 0 10px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bl-muted);
}
.locale-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.top nav .locale-list a,
.locale-off {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  padding: 8px 10px;
  border: 0;
  border-radius: 10px;
  font-family: var(--bl-font-text);
  font-size: 0.92rem;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--bl-ink-900);
  text-decoration: none;
  white-space: normal;
}
.top nav .locale-list a:hover { background: var(--bl-blue-tint); color: var(--bl-ink-900); }
.top nav .locale-list a[aria-current="page"] { background: var(--bl-blue-tint); font-weight: 600; }
.locale-code {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 28px;
  height: 20px;
  border-radius: 5px;
  background: var(--bl-surface);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  color: var(--bl-text-2);
}
.locale-money { margin-inline-start: auto; font-size: 0.78rem; color: var(--bl-muted); font-variant-numeric: tabular-nums; }
.locale-off { color: var(--bl-muted); cursor: default; }
.locale-off em { margin-inline-start: auto; font-style: normal; font-size: 0.74rem; }
@media (min-width: 901px) and (max-width: 1180px) {
  .top nav { gap: 18px; }
  .top nav a { font-size: 0.88rem; }
  .top nav .nav-cta { padding: 10px 16px; }
}
@media (max-width: 900px) {
  .top nav .locale { width: 100%; margin-top: 14px; }
  .top nav .locale-btn { width: 100%; height: 46px; justify-content: flex-start; font-size: 0.95rem; }
  .top nav .locale-btn .locale-chev { margin-inline-start: auto; }
  .top nav .locale-panel {
    position: static;
    width: auto;
    margin-top: 8px;
    padding: 12px;
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
    box-shadow: none;
  }
  .top nav .locale-list a,
  .top nav .locale-list a:last-child { border-bottom: 0; }
}

/* --- Warteliste und Hinweise der deutschen Seiten -------------------------- */
.market-note {
  max-width: 70ch;
  margin: 34px 0 26px;
  padding: 14px 18px;
  border: 1px solid var(--card-line);
  border-radius: var(--bl-radius-panel);
  background: var(--bl-blue-tint);
  color: var(--bl-text-2);
  font-size: 0.92rem;
  line-height: 1.55;
}
.market-note strong { color: var(--bl-ink-900); }
.waitlist { margin-top: 30px; }
.waitlist select { appearance: auto; }
.waitlist .f-note a { color: var(--bl-accent-text); }
.waitlist-privacy { max-width: 62ch; line-height: 1.55; }
.waitlist-done {
  margin-top: 30px;
  padding: 20px 22px;
  border: 1px solid var(--bl-success);
  border-radius: var(--bl-radius-panel);
  background: var(--bl-ground);
}
.waitlist-done h3 { margin: 0 0 6px; font-size: 1.1rem; }
.waitlist-done p { margin: 0; color: var(--bl-text-2); }
.legal-lang {
  padding: 12px 16px;
  border: 1px solid var(--card-line);
  border-radius: var(--bl-radius-panel);
  background: var(--bl-blue-tint);
  font-size: 0.92rem;
}
@media (max-width: 760px) {
  .waitlist .f-row { grid-template-columns: minmax(0, 1fr); }
}
/* ===========================================================================
   Site review, 2026-09-17
   =========================================================================== */

/* --- Hero: the copy, a capability row, and Belle on video beside it ------- */
/* Row spacing lives on the pills (`.hero-can > li`, further down), not in this
   `gap`, so the invisible line break between the claims and the channels costs
   no space. Hence `row-gap: 0` and the container's top margin paying back the
   one gap the first row now carries itself. */
.hero-can {
  --hero-can-row-gap: 8px;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0 10px;
  margin: calc(24px - var(--hero-can-row-gap)) 0 0;
  padding: 0;
}
.hero-can li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px 6px 10px;
  border: 1px solid var(--card-line);
  border-radius: var(--bl-radius-pill);
  background: var(--bl-ground);
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--bl-ink-900);
}
.hero-can li::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--bl-blue);
}
/* A line break inside the wrapping row, so the channels keep their own line.

   "Put Phone WA and Website in one row" (founder, 4 Oct 2026). Split into
   three pills they wrapped wherever the previous two happened to leave off,
   and Website orphaned onto a line of its own — three facts reading as two
   and a stray.

   A zero-height item at full width is how a wrapping flex row is broken on
   purpose; nothing in CSS breaks before a flex item directly. It carries none
   of the pill styling above, and the markup marks it `aria-hidden`, so a
   screen reader still hears four claims rather than five.

   From 600px up only. On a phone this hero is already a pixel fight — `e2e
   video` holds Belle's icons and the reassurance line above the fold at
   375x667 — and a guaranteed extra row is the one thing that budget cannot
   pay for. There the pills wrap as they always did. */
/* The line break that keeps the channels on a row of their own.

   "Put Phone WA and Website in one row" (founder, 4 Oct 2026), and then "phone
   whatsapp and website not on the same line in mobile version" (5 Oct) — it was
   gated above 600px, so on a phone the three still wrapped wherever the two
   claims before them happened to end. It is unconditional now: counted on the
   live page the row count is the same either way at phone width, so putting
   them together costs nothing.

   Four classes, deliberately. The 600–900px band styles these pills with
   `.hero-demo.has-video-hero .hero-can li` — three classes and an element — and
   a two-class reset loses to it, so the break kept that rule's 5px of vertical
   padding and stood 10px tall instead of nothing. Measured on belline.ai,
   5 Oct 2026: 16px of space above the channels and 6px below, which is exactly
   the unevenness the founder reported twice. Specificity, not order, is what
   was wrong.

   Spacing is the other half, and a negative margin is not how to get it. A
   zero-height line is still a line, and a wrapping flex container puts a
   row-gap on *both* sides of it, so the break doubles the space above the
   channels. `margin-top: -6px` looks like it should take one gap back; it does
   not. Row-gap is distributed between flex *lines*, and an item's own margins
   do not shrink it — measured on belline.ai 5 Oct 2026, the gaps were [12, 6]
   with the negative margin, and [12, 6] with it on the bottom, and [12, 6]
   with it on both. That is why the founder reported the same unevenness after
   it shipped.

   So the gap moves off the container and onto the items: `row-gap: 0`, and
   every pill carries its own `margin-top`. Then the break, with no margin of
   its own, costs nothing at all and the three rows sit evenly — [6, 6] in the
   same measurement. The container's own top margin loses one gap to pay for
   the margin the first row now has, so the block as a whole has not moved. */
.hero-can > li {
  margin-top: var(--hero-can-row-gap, 8px);
}
.hero-can .can-break,
.hero-demo.has-video-hero .hero-can .can-break {
  display: block;
  width: 100%;
  height: 0;
  padding: 0;
  border: 0;
  background: none;
  margin: 0;
}
.hero-can .can-break::before,
.hero-demo.has-video-hero .hero-can .can-break::before {
  display: none;
}
/* The calendar claim carries both its forms (site-flags.ts, `canEvery`). The
   long one is the default and the short one appears only below 400px, where
   the long one wraps to two lines. */
.hero-can .cal-short { display: none; }
/* The three steps under the capability row (video-first repositioning,
   2026-09-24): Belle reads your website → paste one line → she answers.
   Numbered, because the point of them is that there are only three and they
   happen in that order — a bulleted list of the same words would read as
   three features. The counter is drawn rather than left to the marker so the
   numeral sits on the text's baseline and takes the accent. */
.hero-steps {
  list-style: none;
  counter-reset: hero-step;
  display: grid;
  gap: 10px;
  margin: 22px 0 0;
  padding: 0;
  max-width: 44ch;
}
.hero-steps li {
  counter-increment: hero-step;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: baseline;
  gap: 10px;
  font-size: 1rem;
  color: var(--bl-ink-900);
}
.hero-steps li::before {
  content: counter(hero-step);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--bl-accent-text);
}

.hero-note { display: grid; gap: 4px; margin-top: 18px; }
.hero-note .gen,
.hero-note-lead { color: var(--bl-ink-900); font-weight: 500; }
.hero-note-more { color: var(--bl-muted); }

/* Centred in its column (site review, 2026-09-17). */
.hero-video {
  margin: 0;
  width: 340px;
  max-width: 100%;
  justify-self: center;
  display: grid;
  gap: 22px;
  justify-items: center;
  text-align: center;
}
/* The slot holds either the still face or, with video on, Belle's real bubble
   (320 px of face and her row of buttons). Its height is kept while she floats
   during a call, so the hero does not jump. */
.hv-slot {
  position: relative;
  display: grid;
  justify-items: center;
  width: 100%;
  padding-top: 56px;
}
/* The slot's landed height, which is the sum of what stands in it:
   56px padding-top + the circle + 14px gap + the 48px row of icons.
   At 320px that was 438; at 260px (founder, 9 Oct 2026) it is 378. Get this
   wrong and the slot resizes as Belle arrives, which is the "hero's slot moved
   as Belle landed" failure in site-review.spec.ts — it caught exactly this
   when the circle shrank and this number did not. */
.hero-video.has-bubble .hv-slot { min-height: 378px; }
.hv-face {
  display: grid;
  place-items: center;
  width: min(300px, 76vw);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 38%, var(--bl-navy-card), var(--bl-navy) 72%);
  background-size: cover;
  background-position: center;
  /* A ring of page colour, then the brand blue — the ring the demo page's call
     panel draws round Belle (embed/[key]/video/VideoPanel.tsx, .bv-circle), and
     the one the live bubble draws now too (public/embed-video.js). The grey
     hairline that was here read as a stock portrait; the blue says the circle
     is something to press. Founder, f6. */
  box-shadow: 0 0 0 3px var(--bl-ground), 0 0 0 5px var(--bl-blue), 0 24px 48px -28px rgba(29, 29, 31, 0.45);
}
.hv-face svg { width: 44%; height: 44%; }
.hv-mark { fill: var(--bl-blue-lit); }
.hero-video.has-poster .hv-face svg { display: none; }
.hero-video.has-bubble .hv-face { display: none; }
.hero-video.has-bubble .hv-cta { display: none; }
.hv-cap { display: grid; gap: 10px; justify-items: center; }
.hv-head { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 8px; margin: 0; }
.hv-title {
  font-family: var(--bl-font-display);
  font-weight: var(--bl-weight-heading);
  font-size: 1.15rem;
  letter-spacing: -0.015em;
  color: var(--bl-ink-900);
}
.hv-text { margin: 0; max-width: 34ch; font-size: 0.92rem; color: var(--bl-text-2); }
@media (max-width: 900px) {
  .hero-video { justify-self: center; width: 100%; }
  .hv-slot { padding-top: 0; }
  .hero-video.has-bubble .hv-slot { min-height: 0; }
}
/* Room above her for the "AI receptionist" badge, which takes none for itself.

   `.bvb-tags` is absolutely positioned on the bubble — `top: 0`, then lifted a
   whole height plus 8px — so layout cannot see it and nothing above it knows to
   move out of the way. The slot's `padding-top` is the only thing reserving it.

   Below 400px that padding is 74px and the badge sits comfortably inside it.
   Between 401 and 900 the rule above zeroed it and nothing put it back, so the
   badge hung 30px into whatever the hero's claims ended with. Measured on the
   live site, 8 Oct 2026: with the padding at 0 the badge overlaps "Tells Slack
   and HubSpot" by 20px, which is what the founder reported. Most phones are in
   that band — 412, 428, 430 — and the widths below 400 that the hero work was
   measured at were not.

   74px, the same figure the band below 400px uses.

   This shipped as 36px first, on one measurement: the badge looked like it
   reached 30px above the circle, so 36 cleared it by 6. It does not generalise.
   How much room the badge needs is not just its own height — it is that, minus
   however much space already sits between where the claims stop and where the
   slot starts, and that gap changes with every width, because the claims wrap
   differently. Measured again on the live page after it shipped, at a layout
   where the claims end tight against the slot: 0px overlapped by 44, **36px
   still overlapped by 8**, and 74px cleared by 30.

   So the number that works everywhere is the one that was already working
   everywhere below 400px. Paired with the pending one further down — see the
   warning there, which this band had been breaking in the other direction. */
@media (min-width: 401px) and (max-width: 900px) {
  .hero-video.has-bubble .hv-slot { padding-top: 74px; }
}
/* In a call, on a phone, the 74px above her holds only the "AI receptionist"
   badge: the greeting it was sized for is not shown in a call. Giving the rest
   back keeps the call's controls on the screen. With every claim live, a call
   grown in the hero of a 390x844 phone ended 2 to 5px below it, End call
   included (the video e2e, 14 Oct 2026). Only while the call lasts
   (site.js `is-calling`), so her resting place never moves. */
@media (max-width: 900px) {
  .hero-video.has-bubble.is-calling:not(.is-mini-hero) .hv-slot { padding-top: 40px; }
}
/* With Belle's bubble in the slot (site.js), the face is the button: under it
   only her icons and the included line. × makes her small for the session:
   the demonstration goes, and the small face floats in the corner (on a
   phone it waits in the hero first: `.is-mini-hero`, further down). */
.hero-video.has-bubble .hv-head,
.hero-video.has-bubble .hv-text { display: none; }
.hero-video.is-small { display: none; }
.video-bubble .bvb-circle { cursor: pointer; }
.video-bubble.is-call .bvb-circle { cursor: default; }
@media (max-width: 900px) {
  /* A phone, on load: Belle large in the first screen, straight under the
     headline and the pills, then the button, the paragraph and the notes. */
  .hero-demo.has-video-hero { display: flex; flex-direction: column; align-items: stretch; gap: 0; }
  .hero-demo.has-video-hero .hero-copy { display: contents; }
  .hero-demo.has-video-hero .hero-video { order: 1; margin-top: 10px; }
  .hero-demo.has-video-hero .cta-row { order: 2; margin-top: 22px; }
  .hero-demo.has-video-hero .lead { order: 3; }
  .hero-demo.has-video-hero .hero-note { order: 4; }
  .hero-demo.has-video-hero .hero-video { gap: 6px; }
  /* Tighter pills, so they take two rows rather than three and Belle's icons stay in the first screen. */
  /* `row-gap: 0` and the pills' own `margin-top` carry the rows apart — see the
     `.hero-can > li` note above. The top margin is the intended 18px less the
     one gap the first row brings with it. */
  .hero-demo.has-video-hero .hero-can { --hero-can-row-gap: 6px; gap: 0 6px; margin-top: calc(18px - var(--hero-can-row-gap)); }
  .hero-demo.has-video-hero .hero-can li { padding: 5px 11px 5px 9px; gap: 7px; font-size: 0.84rem; }
  /*
    Tighter again, because this row keeps being given more to say.

    It was three pills and a calendar line. It is now four — Instagram joined
    them — plus the calendar line and a tools line ("Tells Slack and HubSpot"),
    and at 390x844 that put the "included" line 12px past the first screen.
    `site-review.spec.ts` caught it, which is the second time today that test
    has earned its place.

    Trimming the gaps rather than dropping a claim: each of those lines is
    something the founder asked to have said there, and a first screen is a
    budget to spend rather than a reason to say less. The type stays as it
    was — these are read at a glance, and shrinking them is how a row of facts
    becomes a row of footnotes.
  */
  .hero-demo.has-video-hero .hero-can { --hero-can-row-gap: 4px; gap: 0 5px; margin-top: calc(14px - var(--hero-can-row-gap)); }
  .hero-demo.has-video-hero .hero-can li { padding: 4px 9px 4px 8px; gap: 6px; }
  .hero-demo.has-video-hero .hero-can li::before { width: 6px; height: 6px; }
}

/*
  The smallest phone, where the row is made to fit rather than cut.

  At 375x667 — an iPhone SE, still the shortest screen worth designing for —
  all six claims and a video hero were 15px too tall, and four passes of
  trimming gaps and type got nowhere near it. Measuring the row instead of
  squeezing it found two things, and both are waste rather than air:

    **Website was alone on a row of its own.** Phone, WhatsApp and Instagram
    filled 256.9px of the 335px available; Website needed 339.2px, so it
    wrapped and took a whole 24px row to hold one word with 258px of empty
    space beside it. It misses by 4.2px. The dot and its gap give that back
    below — two pixels a pill, four pills — and the four channels sit on one
    line.

    **The calendar line said all four calendars and wrapped to two.** It names
    one here instead; see `.cal-long` / `.cal-short` in site-flags.ts. The
    other three are named on the strip, the cards and the pricing, each of
    which this reader reaches by scrolling.

  Together that is 43px, so every claim is kept, including the tools line, and
  the first screen has about 27px in hand. The type still gives, because this
  is also where the row is tightest horizontally.

  If a seventh claim is ever added, this is the place it will be felt first,
  and the honest move then is to edit the row rather than squeeze it again.
*/
@media (max-width: 400px) {
  /*
    The 4.2px that keeps Website off the channel row, taken twice over: once
    from the space between each dot and its word, once from the pill's own
    sides. Two pixels each, four pills, eight pixels a go — which turns a
    4.2px miss into about 12px in hand. The dot still reads as a dot; it
    simply stands closer to what it marks.
  */
  .hero-demo.has-video-hero .hero-can li { font-size: 0.78rem; padding: 3px 7px 3px 6px; gap: 4px; }
  /*
    And the sentence above them takes one step down, so four channel names
    still set two lines here.

    "Your AI receptionist for phone, WhatsApp, Instagram and your website." is
    eleven characters longer than the three-name version (founder, f27, asking
    for Instagram after WhatsApp). At the clamp's own size on a 375px screen
    that is a third line, which is 25px, and the first screen had about 13 of
    them spare. At 1.16rem it is two lines again with room over.

    Only below 400px. Every wider screen keeps the clamp, where the sentence
    has never needed help.
  */
  .hero-demo.has-video-hero .hero-sub {
    font-size: 1.16rem;
    /*
      And the measure comes off, because at this size it is what binds.

      `.hero-sub` is capped at 26ch. At the clamp's own size on a 375px screen
      26ch is wider than the column, so the cap never did anything and the note
      beside it says so. One step smaller it is about 239px against a 335px
      column — so the cap, not the screen, was holding the sentence to three
      lines, and shrinking the type on its own changed nothing.
    */
    max-width: none;
  }
  /* One calendar named rather than four, so the line does not wrap. */
  .hero-demo.has-video-hero .hero-can .cal-long { display: none; }
  .hero-demo.has-video-hero .hero-can .cal-short { display: inline; }
  /* Room above the face for the "AI concierge" pill and, above that, "Hi, I'm Belle — tap to
     talk", which a phone shows too. The badge stands 8px clear of the ring and is ~22px tall,
     so the greeting sits at 36px and the slot has to hold both.

     This one is load-bearing beyond the look of it: `body.video-pending`
     reserves the same 74px before Belle arrives, and site-review.spec.ts
     measures that the slot does not move when she lands. Letting it fall out
     of this block — which is what happened for a few minutes on 8 Oct 2026,
     by closing the block early to add a narrower one — makes the hero jump
     72px at the handover on every 381-400px phone. */
  .hero-video.has-bubble .hv-slot { padding-top: 74px; }
  .video-bubble:not(.is-call):not(.is-mini) .bvb-caption { display: block; bottom: calc(100% + 36px); }
  .video-bubble .bvb-row { margin-top: 12px; }
}
/* And the sentence takes one more step down on the narrowest phone there is.
   A 375px screen gives it a 335px column against the 390's 350, and those
   fifteen pixels are the difference between two lines and three for the
   four-name version. Measured at both widths rather than guessed.

   Nothing else belongs in here: everything above is written for the whole
   400px range. */
@media (max-width: 380px) {
  .hero-demo.has-video-hero .hero-sub { font-size: 1.06rem; }
}
/* On a phone the headline gives, because the repositioning made it longer.
   "Someone always answers." set two lines at 2.55rem; "Put a receptionist on
   your website in five minutes." sets three, and a third line at that size is
   43.6px of first screen that was not there to spend. Under Belle's circle sit
   her row of icons and "Included in every plan", and her icons are the hero's
   whole promise: that a visitor can talk to her now, without scrolling. A
   headline that pushes them under the fold argues against its own sentence.

   So the headline is set at 2rem on a phone. Three lines at 2rem is 99.8px
   against the old headline's 87.3px, so the new sentence still takes more of
   the first screen than the old one did — it says more, and it is given room
   to. The wrap does not move: `.hero h1` is capped in `ch`, which scales with
   the size, so it breaks in the same three places.

   Phones only (520px), and both of them, because three lines is three lines
   whatever the screen is tall. 390x844 is the one that fails first, and not on
   the hero at all: in a call the circle grows into a 9:16 frame 425.7px tall
   from the top it rests at, so every pixel above her counts twice there. That
   frame is what `expectInCall` in tests-video/video.spec.ts measures. */
@media (max-width: 520px) {
  .hero-demo.has-video-hero h1.display { font-size: 2rem; line-height: 1.04; }
}
/* A short phone (375x667): a little smaller, so the face, her icons and the
   included line all fit the first screen.

   214px used to be that number and it stopped fitting — "Included in every
   plan" sat about 7px under the fold on a 667-tall screen, which the
   site-review spec measures. The circle cannot just shrink to absorb it: the
   same spec holds her to at least 210px on a phone, on the grounds that a
   face too small to read is not worth reserving a first screen for. So she
   sits on the 210 floor and the rest comes out of the air above her.

   More of it comes out now, because the home page carries more words than
   the page this was measured on. The eyebrow and the third claim are written
   from the flags: with the telephone and WhatsApp live, the eyebrow is "AI
   receptionist for your website, telephone & WhatsApp" and runs to two lines,
   and "Books into Google Calendar, Outlook or Calendly" is one claim that
   wraps to two — together 42px more than a build with no credentials renders,
   and 31px more than the first screen has. A flag-off build is what
   site-review.spec.ts measures, so nothing caught it.

   So the gaps give it up, and now the headline does too — a second step down
   from the 2rem the block above sets, for the same reason the circle and the
   pills take one here. On a 667-tall screen "Included in every plan" is the
   last thing above the fold and it has 10.8px to spare at 1.8rem; at 2rem it
   sat 0.9px below it. The note above the 520px block has the rest. */
@media (max-width: 520px) and (max-height: 720px) {
  /* Her circle was held at 210px while the first screen was short of room: it
     is the obvious place to find twenty pixels and it was spoken for, because
     a face smaller than that stops reading as a person on a phone.

     248 since 8 October 2026, because the room came back twice over. The
     claims row stopped wasting a line on Website and a second one on the
     calendar sentence (43px, see the 400px block above), and "Included in
     every plan." came off the figure for being untrue (23px). The founder
     asked for the room to go to her: "might want to make Belle a bit larger so
     she catches the eye of website visitors better" (f27).

     Measured at 375x667 with every flag on, which is the tightest the page
     ever gets: her icons then end about 13px above the fold. That margin is
     the budget for the next claim somebody adds to this hero — spend it there,
     not on her.

     234 since 15 October 2026: "Start free" moved above her (launch audit,
     H08/M-04) and its 50px came out of that margin, her 14px and the air
     around the button (the block after "A phone's first screen" near the
     end of this file). She is still over the 232px floor e2e video holds. */
  .video-bubble.bvb:not(.is-call) { --bvb-call: min(234px, calc(100vw - 40px)); }
  .hero-demo.has-video-hero h1.display { font-size: 1.66rem; line-height: 1.02; }
  .hero-demo.has-video-hero .hero-video { margin-top: 0; }
  .hero .eyebrow { margin-bottom: 5px; line-height: 1.3; }
  /* Tightened again on 4 Oct 2026, for the fourth bullet.

     The capability row gained "Phone, WhatsApp and website" (site-flags.ts,
     `heroChannelsBullet`), which is one more wrapped row at this width, and
     `e2e video` caught Belle's icons landing 3.7px below the first screen —
     on a block whose own note above says it used to clear by 0.9px. It was
     always going to be the next addition that broke it.

     6px of margin and 2px of padding a row buys back about 8px: the overflow
     and a little. If a fifth bullet is ever wanted here this block is out of
     road, and the headline is what should give at this height instead. */
  .hero-demo.has-video-hero .hero-can { --hero-can-row-gap: 2px; row-gap: 0; margin-top: calc(4px - var(--hero-can-row-gap)); }
  /* `.hero-demo.has-video-hero .hero-can li` and not `… ul li`: the 900px
     block sets this padding with three classes, and two classes plus two
     elements loses to it. */
  .hero-demo.has-video-hero .hero-can li { padding-top: 1px; padding-bottom: 1px; }
  .hero-demo.has-video-hero .bvb-row { margin-top: 2px; }
  /* A rule shrinking "Included in every plan." stood here. That line came off
     the hero on 8 Oct 2026 for being untrue (f27), so the rule went with it —
     along with its two siblings elsewhere in this file. */
}

/* --- Belle's place, before the widget has answered --------------------------
   `body.video-pending` is in the markup of a build with video live
   (src/lib/site-flags.ts). It is the first painted frame's promise that a live
   bubble is coming: the still face is already the bubble's size, in the
   bubble's place, with the bubble's room under it for her icons, and the
   heading, the paragraph, the "Talk to Belle" button and the three floating
   buttons — everything the bubble replaces — are not painted at all. The page
   is finished from the first frame and nothing moves when she lands.

   site.js takes the class off once it knows (`decided`): the bubble is in the
   hero, so `has-bubble` and `has-video-bubble` hold the same things back and
   the real icons take the room this reserved; or there will be no bubble, and
   the hero's own heading, button and floating buttons appear. Nothing here is
   ever on screen at the same time as the live bubble.

   `--hv-call` is `--bvb-call` from public/embed-video.js, which is what the
   resting bubble's circle measures, plus the short-phone override above.
   check:webchat holds the two to each other — they are the same number in two
   files and drifting apart is a visible jump. */
body.video-pending { --hv-call: min(260px, calc(100vw - 48px), calc(100dvh - 250px)); }
@media (max-width: 520px) {
  body.video-pending { --hv-call: min(240px, calc(100vw - 40px), calc(100dvh - 230px)); }
}
@media (max-width: 520px) and (max-height: 720px) {
  /* The same 234 the live bubble takes on a short phone (the block above
     "Her circle was held at 210px"). These two are one number in two files:
     the page reserves this, she arrives at that, and if they part the whole
     hero jumps at the handover. */
  body.video-pending { --hv-call: min(234px, calc(100vw - 40px)); }
}
/* (The three floating buttons step aside for a pending call; that rule lives
   with them, under "The floating buttons".) */
body.video-pending .hero-video .hv-head,
body.video-pending .hero-video .hv-text,
body.video-pending .hero-video .hv-cta { display: none; }
body.video-pending .hero-video .hv-face { width: var(--hv-call); }
/* The room her row of icons takes, held open: `.bvb-row` is one 48px button
   (46px on a phone) 14px under the circle (12px on a phone, above). */
body.video-pending .hero-video .hv-slot::after {
  content: "";
  display: block;
  width: 1px;
  height: 48px;
  margin-top: 14px;
}
@media (max-width: 900px) {
  /* The same 74px `.hero-video.has-bubble .hv-slot` reserves above, and it has
     to be the same number. This is the space the page holds before Belle
     arrives; that is the space she takes when she does. They were both 42px
     until the "AI concierge" pill moved clear of her ring and the landed
     figure grew to 74 — and only the landed one was changed, so the page
     reserved 42, took 74, and everything below jumped 32px at the handover.
     The founder saw it as the old layout "shifting" (2026-09-20). If one of
     these two numbers changes, the other one changes with it. */
  body.video-pending .hero-video .hv-slot { padding-top: 74px; }
  body.video-pending .hero-video .hv-slot::after { margin-top: 12px; }
}
/* And the same pairing for 401–900.

   This band had the fault the warning above describes, running the other way:
   the page reserved 74px and Belle landed in 0, so everything below jumped *up*
   74px at the handover. Both numbers are 74 here now — they were briefly 36,
   until measuring the live page showed 36 was not enough room for the badge at
   every width. If one changes, so does the other —
   `.hero-video.has-bubble .hv-slot` further up. */
@media (min-width: 401px) and (max-width: 900px) {
  body.video-pending .hero-video .hv-slot { padding-top: 74px; }
}
@media (max-width: 520px) {
  body.video-pending .hero-video .hv-slot::after { height: 46px; }
}

/* --- What Belline does: four entries, video first ------------------------- */
#channels .channels-4:not(.channels-3) > li:first-child { border-color: var(--bl-blue); box-shadow: inset 0 0 0 1px var(--bl-blue); }

/* --- Who it is for: three use cases, then the rest ------------------------- */
#for .uses {
  list-style: none;
  margin: 44px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
}
#for .uses li {
  padding: 26px 24px 28px;
  background: var(--bl-ground);
  border: 1px solid var(--card-line);
  border-radius: var(--card-radius);
}
#for .uses h3 {
  margin: 0 0 8px;
  font-family: var(--bl-font-display);
  font-weight: var(--bl-weight-heading);
  font-size: 1.15rem;
  letter-spacing: -0.015em;
  color: var(--bl-ink-900);
}
#for .uses p { margin: 0; font-size: 0.95rem; color: var(--bl-text-2); }
#for .kinds-lead { margin: 32px 0 0; font-weight: 600; color: var(--bl-ink-900); }
#for .kinds { margin-top: 14px; }
@media (max-width: 900px) {
  #for .uses { grid-template-columns: minmax(0, 1fr); gap: 14px; }
}

/* --- What your team gets: the rows beside the example ---------------------- */
/* One column since the example conversations moved up to their own section
   (#every-channel): what is left is the four claims, and a 460px empty track
   beside them was a hole. */
.receive { margin-top: 48px; }
#stop .receive .stop-rows { grid-template-columns: minmax(0, 1fr); gap: 14px; margin-top: 0; }
#stop .receive .stop-rows > div { padding: 22px 22px 24px; }
#stop .receive .stop-small { margin: 6px 0 0; }
/* The example conversations, now the whole of #every-channel rather than a
   side panel. Wider than the 460px track they used to sit in. */
.example { display: grid; gap: 14px; min-width: 0; margin-top: 44px; }
.example .stage { width: auto; }
.stage-result {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 14px;
  align-items: start;
}
.stage-result .call-sent { margin: 0; background: var(--bl-ground); border: 1px solid var(--card-line); border-radius: var(--card-radius); padding: 14px; }
.stage-result .call-sent dl div { grid-template-columns: 5.4em minmax(0, 1fr); }
.stage-result .cal {
  margin: 0;
  min-width: 0;
  background: var(--bl-ground);
  border: 1px solid var(--card-line);
  border-radius: var(--card-radius);
  font-size: 0.86rem;
  line-height: 1.45;
  color: var(--bl-ink-900);
}
.stage-result .cal-head { padding: 10px 12px; }
.stage-result .cal-body { padding: 12px 10px 10px 6px; }
.stage-result .cal-ev-new { grid-row: 3 / 9; }
.cal-ev-new.is-booked { background: var(--bl-success-tint); border: 1.5px solid var(--bl-success); }
.cal-ev-new.is-booked .cal-new-k { color: var(--bl-success); }
.cal-ev-new.is-booked .cal-new-state { background: var(--bl-ground); color: var(--bl-success); }
#stop .stage-result p,
#stop .stage p { color: inherit; }
#stop .stage-result .call-sent-head { color: var(--bl-success); }
#stop .stage-result dt { color: var(--bl-muted); }
#stop .stage-result dd { color: var(--bl-ink-900); }
@media (max-width: 1100px) {
  .receive { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .example { max-width: 560px; }
}
@media (max-width: 520px) {
  .stage-result { grid-template-columns: minmax(0, 1fr); }
}

/* --- Integrations: connects today, coming soon, and the roadmap, quieter --- */
.connects { padding: 8px 0 72px; background: var(--bl-ground); }
.connects-groups { display: grid; gap: 28px; }
.connects-group-h {
  margin: 0 0 10px;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--bl-text-2);
}
.connects-groups .connects-list {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  border: 0;
}
.connects-groups .connect,
.connects-groups .connect:first-child,
.connects-groups .connect:nth-child(n) {
  flex-direction: row;
  align-items: center;
  gap: 12px;
  padding: 14px 18px;
  border: 1px solid var(--card-line);
  border-radius: var(--card-radius);
  background: var(--bl-ground);
}
.connects-groups .connect-name { color: var(--bl-ink-900); }
.connects-roadmap .connect,
.connects-roadmap .connect:first-child,
.connects-roadmap .connect:nth-child(n) {
  gap: 8px;
  padding: 8px 12px;
  border-color: var(--bl-rule-soft);
  background: transparent;
}
.connects-roadmap .connect-logo { width: 24px; height: 24px; border-radius: 6px; opacity: 0.75; }
.connects-roadmap .connect-name { font-size: 0.92rem; color: var(--bl-muted); }
.connects-roadmap .state { height: 20px; padding: 0 8px; font-size: 0.72rem; }
.connects-roadmap .connects-group-h { color: var(--bl-muted); font-weight: 500; }
@media (max-width: 600px) {
  .connects-groups .connect,
  .connects-groups .connect:first-child,
  .connects-groups .connect:nth-child(n) { width: 100%; }
  .connects-roadmap .connect,
  .connects-roadmap .connect:first-child,
  .connects-roadmap .connect:nth-child(n) { width: auto; }
}

/* --- Pricing: trial and cycle on one bar, equal cards, shared features ---- */
.price-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px 24px;
  margin-top: 36px;
}
.price-bar .cycle { margin: 0; }
.price-trial {
  margin: 0;
  padding: 10px 16px;
  border-radius: var(--bl-radius-pill);
  background: var(--bl-blue-tint);
  color: var(--bl-ink-900);
  font-size: 0.95rem;
}
#price .plan-allow { gap: 8px; margin-bottom: 18px; padding-bottom: 18px; border-bottom: 1px solid var(--card-line); }
#price .plan-allow li { color: var(--bl-ink-900); font-weight: 500; }
#price .plan-allow li.allow-video::before { background: var(--bl-success); }
#price .plan-diff li { font-size: 0.88rem; }
#price .plan .btn { justify-self: start; }
/* The text-only plan, under the three cards rather than beside them.
   Quiet: it is an aside to the product, not a fourth option competing with
   it — but it keeps the price and what it leaves out, because demoting a plan
   must not mean hiding either. */
.plan-aside {
  display: grid;
  grid-template-columns: minmax(0, 260px) minmax(0, 1fr);
  gap: 16px 40px;
  align-items: start;
  margin: 18px 0 0;
  padding: 22px 28px 24px;
  border: 1px solid var(--card-line);
  border-radius: var(--card-radius);
  background: var(--bl-surface);
}
.plan-aside-q { margin: 0 0 4px; font-size: 0.86rem; font-weight: 600; color: var(--bl-accent-text); }
.plan-aside-name { margin: 0; font-family: var(--bl-font-display); font-weight: var(--bl-weight-heading); font-size: 1.15rem; }
.plan-aside-price { margin: 8px 0 0; display: grid; gap: 2px; }
.plan-aside-price .amt { font-size: 1.5rem; font-weight: 500; letter-spacing: -0.02em; }
.plan-aside-price .per, .plan-aside-price .billed { font-size: 0.8rem; color: var(--bl-text-2); }
.plan-aside-a { margin: 0; font-size: 0.92rem; line-height: 1.55; color: var(--bl-text-2); max-width: 58ch; }
.plan-aside-lines { margin: 12px 0 16px; padding: 0; list-style: none; display: grid; gap: 5px; font-size: 0.88rem; }
.plan-aside-lines li { padding-inline-start: 18px; position: relative; color: var(--bl-text-2); }
.plan-aside-lines li::before { content: ""; position: absolute; inset-inline-start: 0; top: 0.55em; width: 6px; height: 6px; border-radius: 50%; background: var(--bl-rule-strong); }
.plan-aside .btn { justify-self: start; }
@media (max-width: 720px) { .plan-aside { grid-template-columns: minmax(0, 1fr); gap: 14px; padding: 18px 20px 20px; } }

.plan-shared {
  margin-top: 20px;
  padding: 22px 28px 24px;
  border: 1px solid var(--card-line);
  border-radius: var(--card-radius);
  background: var(--bl-surface);
}
.plan-shared-h {
  margin: 0 0 12px;
  font-family: var(--bl-font-display);
  font-weight: var(--bl-weight-heading);
  font-size: 1rem;
  color: var(--bl-ink-900);
}
.plan-shared ul {
  list-style: none;
  margin: 0;
  padding: 0;
  columns: 2 260px;
  column-gap: 32px;
}
.plan-shared li { break-inside: avoid; padding-block: 4px; padding-inline: 16px 0; position: relative; font-size: 0.9rem; color: var(--bl-text-2); }
.plan-shared li::before { content: ""; position: absolute; inset-inline-start: 0; top: 0.9em; width: 6px; height: 6px; border-radius: 999px; background: var(--bl-blue); }

/* A plan announced before it can be bought (scripts/site-pricing.ts
   comingSoonBand): quieter than a card, a dashed edge because it is not on
   sale, and its only button opens the sign-up in place. */
.plan-soon {
  margin-top: 20px;
  padding: 22px 28px 24px;
  border: 1px dashed var(--card-line);
  border-radius: var(--card-radius);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px 28px;
  align-items: start;
}
.plan-soon-tag {
  margin: 0 0 4px;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--bl-accent-text);
}
.plan-soon h3 { margin: 0 0 6px; font-family: var(--bl-font-display); font-weight: var(--bl-weight-heading); font-size: 1.1rem; color: var(--bl-ink-900); }
.plan-soon-price { font-weight: 500; color: var(--bl-text-2); font-size: 0.95rem; margin-inline-start: 6px; white-space: nowrap; }
.plan-soon-text p:last-child { margin: 0; font-size: 0.92rem; color: var(--bl-text-2); max-width: 62ch; }
.plan-soon-join summary { list-style: none; cursor: pointer; white-space: nowrap; }
.plan-soon-join summary::-webkit-details-marker { display: none; }
.plan-soon-join[open] { grid-column: 1 / -1; }
.plan-soon-join[open] summary { display: none; }
.plan-soon .waitlist { margin-top: 4px; }
@media (max-width: 700px) {
  .plan-soon { grid-template-columns: minmax(0, 1fr); padding: 20px; }
  .plan-soon .f-row { grid-template-columns: minmax(0, 1fr); }
}
.price-tax { margin: 14px 0 0; font-size: 0.86rem; color: var(--bl-muted); }

/* --- The calculator's label ------------------------------------------------ */
.roi-label {
  margin: 0 0 6px;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--bl-text-2);
}

/* --- Country and language on a wide screen ---------------------------------
   The flag alone between 901 and 1180px, where the menu has no room to spare;
   wider, the flag, the country code, its currency and the language, so
   which page this is reads without opening anything (f31, 14 Oct 2026). */
@media (min-width: 901px) {
  .top nav .locale-btn { height: 36px; padding: 0 10px; gap: 6px; border-color: transparent; color: var(--bl-text-2); font-size: 0.84rem; }
  .top nav .locale-btn:hover { border-color: var(--bl-rule-strong); }
  .top nav .locale-btn .locale-now { font-variant-numeric: tabular-nums; }
}
@media (min-width: 901px) and (max-width: 1180px) {
  .top nav .locale-btn { width: 38px; padding: 0; justify-content: center; gap: 0; }
  .top nav .locale-btn .locale-now {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  .top nav .locale-btn .locale-chev { display: none; }
}

/* --- Belle, carried ---------------------------------------------------------
   One Belle, who travels. There is no second launcher element any more: while
   the hero's circle is on screen there is nothing in the corner, and what
   lands there is the same node that was in the hero.

   The flight is written by site.js as two transforms — one on her, one on her
   circle — and nothing else changes while she is in the air. No width, no
   inset, no reflow: the page is never laid out again between frames, which is
   what keeps this at 60fps on a mid-range phone.

   `data-vb` says where she is: "hero" (in the page's flow), "flight" (carried
   by the scroll) or "corner" (landed, 96 px and laid out at that size, with her icons beside her).

   Reduced motion: she rests in the hero like everybody else, and site.js
   steps her between the two places rather than flying her — so the landing
   transition below is turned off under that query and the step is one frame.
   She used to be cornered from the first paint there, which took the hero's
   demonstration away from every visitor who has Windows' animations off. */
.video-bubble.vb-travel {
  position: fixed;
  left: 0;
  top: 0;
  margin: 0;
  z-index: 41;
  /* The transform is the position: left/top stay at the origin so a frame is
     one composited write and never a layout. */
  transform-origin: 0 0;
  will-change: transform;
}
.video-bubble.vb-travel .bvb-circle { will-change: transform; }
/* Her first frame, wherever it is, is painted rather than animated to
   (site.js `place`): without this she slid from the top left to the corner. */
.video-bubble.vb-instant,
.video-bubble.vb-instant * { transition: none !important; }
/* In the air: only her face. Her icons, the greeting pill, "AI concierge" and
   the × belong to a size she is no longer at. */
.video-bubble[data-vb="flight"] .bvb-row,
.video-bubble[data-vb="flight"] .bvb-caption,
.video-bubble[data-vb="flight"] .bvb-tags,
.video-bubble[data-vb="flight"] .bvb-mock,
.video-bubble[data-vb="flight"] .bvb-shut,
.video-bubble[data-vb="corner"] .bvb-caption,
.video-bubble[data-vb="corner"] .bvb-tags,
.video-bubble[data-vb="corner"] .bvb-mock,
.video-bubble[data-vb="corner"] .bvb-shut {
  opacity: 0;
  pointer-events: none;
}
/* Landed: her icons come back at their own size, beside the small face. They
   are laid out against her box, which is still the call circle's width, so
   `right: 100%` is the left edge of the face itself. */
.video-bubble[data-vb="corner"] {
  transition: transform 0.22s ease, opacity 0.22s ease;
}
.video-bubble[data-vb="corner"] .bvb-row {
  position: absolute;
  margin: 0;
  width: max-content;
  top: 19px; /* (96 - 58) / 2: level with the middle of her face */
  bottom: auto;
  left: auto;
  right: calc(100% + 10px);
  opacity: 1;
  transition: opacity 0.18s ease 0.04s;
}
/* Tucked into the margin where her icons would cover something: the face alone. */
/* Larger icons beside the small face (founder, 21 Sep 2026), the same as
   embed-video.js gives a venue site's small Belle. The corner row is absolute,
   so this moves nothing on the page. */
.video-bubble[data-vb="corner"] .bvb-act { width: 58px; height: 58px; }
.video-bubble[data-vb="corner"] .bvb-act svg { width: 26px; height: 26px; }
@media (max-width: 520px) {
  .video-bubble[data-vb="corner"] .bvb-act { width: 56px; height: 56px; }
}
.video-bubble.vb-tucked .bvb-row { opacity: 0; pointer-events: none; }
/* And out of the way entirely where even the face would (a phone has no margin). */
.video-bubble.vb-away { opacity: 0; pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
  .video-bubble[data-vb="corner"],
  .video-bubble[data-vb="corner"] .bvb-row { transition: none; }
  .video-bubble .bvb-row,
  .video-bubble .bvb-caption,
  .video-bubble .bvb-tags,
  .video-bubble .bvb-shut { transition: none; }
}
/* A phone's corner: Belle at full size, her icons in a row to her left.

   History, because each step was a real complaint. Her icons used to stand
   on end above her face here, one column wide, so that after × she could sit
   beside the hero's words (116px reserved for her) rather than on them. That
   column was about 300px of the screen's right-hand side, and the moment the
   hero scrolled away it sat on the "Talk to your next receptionist" chips
   (founder, 10 Oct 2026). Shrinking her to a 60px face with her icons folded
   behind a tap was tried the same day and refused: she is Belline's
   difference, so she stays full size with every way in showing. The page
   makes room for her instead.

   So on a phone she lands 16px from the bottom-right corner (site.js) at the
   96px the desktop uses, with the call, the chat and WhatsApp in one row to
   her left, vertically centred on her face: a strip along the bottom edge,
   96px tall plus 16px of margin plus the safe area, and never taller. 52px
   icons keep four of them (with Instagram) inside a 375px screen.

   `.video-bubble.bvb[…]` and not `.video-bubble[…]`: embed-video.js injects
   `.bvb.is-mini .bvb-row { bottom: 4px; right: calc(100% + 8px) }` into the
   head at runtime, which lands after this file; the extra class wins. */
@media (max-width: 900px) {
  .video-bubble.bvb[data-vb="corner"] .bvb-row {
    flex-direction: row;
    top: 22px; /* (96 - 52) / 2: level with the middle of her face */
    bottom: auto;
    left: auto;
    right: calc(100% + 10px);
  }
  /* The icons' own glyphs keep the corner's 26px rule above; WhatsApp's mark
     is the whole button (embed-video.js sizes its svg to 100%), so nothing
     here may size the svg more strongly than that rule does. */
  .video-bubble.bvb[data-vb="corner"] .bvb-act { width: 52px; height: 52px; }
  /* The end of the page scrolls clear of her strip: the footer's last line
     ends at least the strip's height (96 + 16) plus the safe area above the
     bottom of the screen. The 220px it already kept for the floating buttons
     is more than that; the safe area is added on top. */
  body.has-video-bubble footer { padding-bottom: calc(220px + env(safe-area-inset-bottom, 0px)); }
  /* After ×, on a phone, she waits in the hero's flow (site.js,
     `smallInHero`): the 96px face where the big one was, her icons in a row
     under her as they are at rest, so the hero's words on a short screen are
     never under her strip. embed-video.js's `.bvb.is-mini .bvb-row` would put
     the row beside her, off the left edge of a centred 96px face; here it is
     laid out under her and centred on her. In flight and landed, the rules
     above take over (`:not(.vb-travel)`). */
  .hero-video.is-mini-hero.has-bubble .hv-slot { padding-top: 32px; }
  .hero-video.is-mini-hero .video-bubble.bvb.is-mini:not(.vb-travel) .bvb-row {
    position: relative;
    top: auto;
    right: auto;
    bottom: auto;
    left: 50%;
    width: max-content;
    margin: 12px 0 0;
    transform: translateX(-50%);
  }
  /* No `scroll-padding-bottom` on the page for her strip. It was tried
     (10 Oct 2026) and it broke the call: a call started further down the page
     floats at the bottom of the screen, inside that padding, and scrolling a
     control of the call into view could never satisfy it — e2e video's "Type
     instead" timed out as "outside of the viewport" on a phone. */
}
/* No entrance animation on Belle's column: an element with a transform
   animation contains fixed descendants, and she is fixed for the whole flight
   — inside a transformed ancestor she would fly within the hero instead. */
.hero-video { animation: none; transform: none; }
.hero-video, .hv-slot { filter: none; perspective: none; }
/* Equal cards, prices on one line: each card takes the grid's seven rows
   (tag, name, who it suits, price, allowances, what differs, button). An
   earlier rule set the cards to flex, which quietly beat the subgrid. */
@supports (grid-template-rows: subgrid) {
  #price .plans .plan { display: grid; grid-template-rows: subgrid; align-content: start; }
  #price .plan .plan-price { align-self: end; }
  #price .plan .plan-diff { align-self: start; }
  #price .plan .btn { align-self: end; }
}
@media (max-width: 1000px) {
  #price .plans { grid-template-rows: none; }
  #price .plans .plan { grid-row: auto; display: flex; }
  /* `align-self` changes axis with the card, and the card changes here.
     Above, the card is a grid and the three rules in the @supports block mean
     "sit at the bottom of your row", which is what lines the three prices up.
     This card is `flex-direction: column`, where the cross axis is horizontal
     and the very same `end` means "sit at the right-hand edge" — so on a phone
     the price and the button were pinned to the right of the card while the
     name and the feature list stayed left (founder, 2026-09-19). Restoring the
     flex defaults puts them back: the price block spans the card and reads
     from the left, and the button hugs the left as `.plan .btn` already says
     at the top of this file. */
  #price .plan .plan-price,
  #price .plan .plan-diff { align-self: stretch; }
  #price .plan .btn { align-self: start; }
}@supports (grid-template-rows: subgrid) {
  #price .plans { row-gap: 0; column-gap: 20px; }
  #price .plan .plan-tag { margin-bottom: 10px; }
  #price .plan .plan-price { margin: 20px 0 18px; }
}

/* ===========================================================================
   Absenderseiten (scripts/site-sender.ts)
   ---------------------------------------------------------------------------
   Vier Domains verschicken unsere Kaltakquise, und wer eine davon in den
   Browser tippt, prüft gerade eine E-Mail. Zwei Dinge gehören deshalb nach
   ganz oben und nebeneinander: die Zusicherung, dass die Nachricht echt ist,
   und Belles Gesicht — dasselbe, das in der E-Mail stand. Das Bild ist der
   einzige Weg zum Produkt auf dieser Seite; verkauft wird hier nichts.
   =========================================================================== */

.sender-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 248px;
  gap: 44px;
  align-items: start;
  /* Der Textspalte bleibt das Lesemaß der Rechtsseiten (~665 px), und Belle
     steht daneben statt allein am rechten Rand von 1200 px. */
  max-width: 920px;
  margin: 24px 0 4px;
}

/* Der Grund, warum es die Seite gibt: größer als der Fließtext, in Tinte
   statt im Grau des Kleingedruckten, und vor allem anderen. */
.legal .sender-yes {
  margin: 0 0 20px;
  padding: 16px 20px;
  border: 1px solid var(--card-line);
  border-radius: var(--bl-radius-panel);
  background: var(--bl-blue-tint);
  font-size: 1.08rem;
  line-height: 1.55;
  color: var(--ink);
}
.legal .sender-yes strong { color: var(--ink); }
.legal .sender-what { margin: 0; }

.sender-belle {
  margin: 0;
  display: grid;
  justify-items: center;
  text-align: center;
  gap: 14px;
}

/* Derselbe Kreis mit blauem Ring wie im Hero der Startseite (.hv-face). Der
   Ring sagt, dass der Kreis zum Drücken da ist; ein grauer Haarstrich hatte
   dort wie ein Stockfoto ausgesehen. Ein Standbild, nie ein Videoanruf —
   diese Besucher haben um keine Vorführung gebeten. */
.sender-face {
  display: block;
  width: 152px;
  aspect-ratio: 1;
  border-radius: 50%;
  overflow: hidden;
  /* Navy stops 2px short of the edge, or it shows as a dark hairline under the
     photo's anti-aliased rim (founder, 13 Oct 2026, on the bubble). */
  background: radial-gradient(closest-side, var(--bl-navy) calc(100% - 2px), var(--paper) calc(100% - 2px));
  box-shadow: 0 0 0 3px var(--paper), 0 0 0 5px var(--bl-blue), 0 24px 48px -28px rgba(29, 29, 31, 0.45);
  transition: transform 0.16s ease, box-shadow 0.16s ease;
}
.sender-face img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sender-face:hover,
.sender-face:focus-visible {
  transform: translateY(-2px);
  box-shadow: 0 0 0 3px var(--paper), 0 0 0 6px var(--bl-blue), 0 26px 52px -26px rgba(29, 29, 31, 0.5);
}

.legal .sender-belle figcaption {
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--ink-2);
  max-width: 34ch;
}
.legal .sender-belle figcaption strong { color: var(--ink); font-weight: 600; }

/* Das Bild allein verrät nicht, dass es ein Link ist. Diese Zeile schon. */
.legal a.sender-meet {
  display: inline-block;
  margin-top: 10px;
  font-weight: 500;
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--bl-blue);
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}
.legal a.sender-meet:hover { color: var(--bl-blue); }

/* Auf dieser Seite schweben keine Knöpfe — keine Glocke, kein Chat, kein
   WhatsApp, weil hier nichts verkauft wird. Der Platz, den der Fuß sonst
   unter 1100 px für sie freihält, ist deshalb nur noch leeres Scrollen. */
@media (max-width: 1100px) {
  .sender-doc footer { padding-bottom: 60px; }
}

@media (max-width: 760px) {
  /* Das Gesicht zuerst, dann die Zusicherung: auf einem Telefon ist
     "nebeneinander" untereinander, und oben steht das Erkennbare. */
  .sender-top { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .sender-belle { order: -1; justify-self: center; gap: 10px; }
  .sender-face { width: 140px; }
  .legal .sender-belle figcaption { max-width: 34ch; }
  .legal a.sender-meet { margin-top: 6px; }
  .legal .sender-yes { font-size: 1.02rem; padding: 14px 16px; }
}

/* ---------------------------------------------------------------------------
   /try — the page paid traffic lands on.

   Everything here is an override of the hero the landing page already has.
   The page's whole job is the bubble and the one action beside it, so two of
   `video-pending`'s hides are undone: the "Talk to Belle" button and the typed
   fallback stay visible while the live bubble is on its way, because on this
   page they are the page, not chrome waiting to be replaced.
   --------------------------------------------------------------------------- */

/* The one action, kept visible in both states.

   The landing page hides this button once the live bubble lands, because there
   the face is the button and a second one beside it is clutter on a page with
   plenty else to do. This page has nothing else to do, it is where paid
   traffic arrives, and a named button is less ambiguous than a face —
   particularly on a phone, where the bubble's own "tap to talk" pill is small.
   So it survives both the pending state and the mounted one.

   The caption's heading and paragraph are deliberately not restored: the
   bubble carries its own "Hi, I'm Belle — tap to talk" pill, and saying it
   twice reads as a mistake. They still appear in the no-bubble fallback,
   which is what they are for. */
body.try.video-pending .hero-video .hv-cta,
body.try .hero-video.has-bubble .hv-cta { display: inline-flex; }

/* (The bell never appears on this page — it has one call to action and the
   bubble's own icons. That rule now lives with the other stand-down states,
   under "The floating buttons".) */

body.try .hv-type {
  margin-top: 14px;
  font-size: 0.95rem;
  color: var(--bl-text-2);
}

/* A 44px target (WCAG 2.5.5), not the line of text it was: about 22px tall
   on a phone (ChatGPT audit, 14 Oct 2026). The padding is the target; the
   negative block margin keeps the sentence where it sat. */
body.try .hv-type .btn-quiet {
  font: inherit;
  min-height: 44px;
  padding: 10px 8px;
  margin-block: -10px;
  border: 0;
  background: none;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: var(--brass-soft);
  text-underline-offset: 4px;
}

body.try .try-what { padding-block: 72px; }
body.try .try-what .display { font-size: clamp(1.7rem, 1rem + 2vw, 2.4rem); }

body.try .try-list {
  margin: 30px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 16px;
  max-width: 62ch;
}

body.try .try-list li {
  padding-inline-start: 22px;
  position: relative;
  line-height: 1.5;
}

body.try .try-list li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 0.62em;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--bl-blue);
}

body.try .try-what .fine { margin-top: 28px; max-width: 62ch; }

/* No dismissing her here.

   Every other page can spare the bubble — this one is the bubble, and a × that
   empties the page is a trap on the page paid traffic lands on. Only while she
   is resting: in a call the same control is how the visitor gets out, and
   hiding it then would be the worse trap. */
body.try .bvb:not(.is-call) .bvb-shut { display: none; }

/* --- Comparison pages (/compare/*) and the trust strip ----------------------
   scripts/seo/render.ts `comparePage`, scripts/site-trust.ts. The Belline
   column carries the one tint on the page, so the eye finds our answer in
   each row without the other product's being made to look worse: same type,
   same weight, same rules. A table that greys the competitor out is the kind
   of slant a reader who has just come from their pricing page notices. */
.vs-verdict {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
  margin-top: 40px;
}
.vs-verdict > div {
  border: 1px solid var(--card-line, var(--rule));
  border-radius: var(--card-radius, 18px);
  padding: 26px 28px;
  background: var(--paper);
}
.vs-verdict > .vs-ours { background: var(--brass-soft); border-color: var(--accent-line); }
.vs-verdict h3 { margin: 0 0 10px; font-family: var(--serif); font-weight: 500; font-size: 1.15rem; letter-spacing: -0.01em; }
.vs-verdict p { margin: 0; color: var(--ink-2); font-size: 0.95rem; }
.vs-list { margin: 0; padding: 0; list-style: none; }
.vs-list li { position: relative; padding-block: 7px; padding-inline: 22px 0; font-size: 0.93rem; color: var(--ink-2); border-top: 1px solid var(--rule-soft); }
.vs-list li:first-child { border-top: 0; }
.vs-list li::before { content: ""; position: absolute; inset-inline-start: 2px; top: 15px; width: 7px; height: 7px; border-radius: 50%; background: var(--accent-line); }

/* On a phone the table scrolls inside its own box, as .legal tables do. */
.vs-wrap { overflow-x: auto; margin-top: 36px; border: 1px solid var(--card-line, var(--rule)); border-radius: var(--card-radius, 18px); }
.vs-table { border-collapse: collapse; width: 100%; min-width: 640px; }
.vs-table th, .vs-table td {
  text-align: start;
  vertical-align: top;
  padding: 16px 18px;
  border-bottom: 1px solid var(--rule-soft);
  font-size: 0.92rem;
  line-height: 1.55;
  color: var(--ink-2);
}
.vs-table tbody tr:last-child th, .vs-table tbody tr:last-child td { border-bottom: 0; }
.vs-table thead th { font-family: var(--serif); font-weight: 600; font-size: 1rem; color: var(--ink); background: var(--paper-2); }
.vs-table tbody th { color: var(--ink); font-weight: 600; width: 22%; }
.vs-table td:nth-child(2), .vs-table thead th.vs-ours { background: var(--brass-soft); color: var(--ink); }
.vs-table td { width: 39%; }

.trust-grid {
  list-style: none;
  margin: 40px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
}
.trust-grid li {
  border: 1px solid var(--card-line, var(--rule));
  border-radius: var(--card-radius, 18px);
  padding: 22px 22px 20px;
}
.trust-grid h3 { margin: 0 0 8px; font-size: 0.98rem; font-weight: 600; color: var(--ink); }
.trust-grid p { margin: 0; font-size: 0.88rem; color: var(--ink-2); }
.foot-trust { font-size: 0.8rem; margin-top: 12px; color: var(--ink-3); }

@media (max-width: 760px) {
  .vs-verdict { grid-template-columns: 1fr; }
}

/* --- What is not on the bill (scripts/site-pricing.ts NOT_ON_THE_BILL) ----- */
.price-absent {
  list-style: none;
  margin: 26px 0 30px;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
}
.price-absent li {
  border: 1px solid var(--card-line, var(--rule));
  border-radius: 999px;
  padding: 9px 16px;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--ink);
  background: var(--paper);
}
.price-absent li::before { content: "✕"; color: var(--brass-fill); margin-inline-end: 7px; font-weight: 700; }

/* --- Footer columns (scripts/site-footer.ts) --------------------------------
   Brand and contact on the left, four columns of links on the right; the
   trust line and the legal line run underneath across the full width. */
.foot-top {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 3fr);
  gap: 40px 56px;
  align-items: start;
}
.foot-brand p { margin-top: 12px; max-width: 34ch; }
.foot-cols { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px; }
.foot-cols h4 {
  margin: 6px 0 12px;
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
}
.foot-cols ul { list-style: none; margin: 0; padding: 0; }
.foot-cols li { font-size: 0.86rem; line-height: 2; }
.foot-cols a { color: var(--ink-2); text-decoration: none; }
.foot-cols a:hover { color: var(--ink); text-decoration: underline; }
footer .foot-trust { margin-top: 32px; padding-top: 18px; border-top: 1px solid var(--rule-soft); max-width: none; }
@media (max-width: 900px) {
  .foot-top { grid-template-columns: minmax(0, 1fr); }
  .foot-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* --- "Or hear her answer as your business" (landing #ask, site.js) --------- */
.demo-box {
  margin-top: 28px;
  max-width: 560px;
  border: 1px solid var(--card-line, var(--rule));
  border-radius: var(--card-radius, 18px);
  padding: 18px 18px 16px;
  background: var(--paper);
}
.demo-box label { display: block; font-weight: 600; font-size: 0.95rem; color: var(--ink); margin: 0 0 4px; }
.demo-box > p { margin: 0 0 12px; font-size: 0.86rem; color: var(--ink-3); }
.demo-row { display: flex; gap: 10px; }
.demo-row input {
  flex: 1;
  min-width: 0;
  height: 46px;
  border: 1px solid var(--card-line, var(--rule));
  border-radius: 999px;
  padding: 0 18px;
  font: inherit;
  color: var(--ink);
  background: var(--paper);
}
.demo-row .btn { white-space: nowrap; }
.demo-error { margin: 8px 0 0; font-size: 0.84rem; color: var(--bl-danger); }
.demo-status { margin: 8px 0 0; font-size: 0.9rem; color: var(--ink-2); }
.demo-status .btn { margin-inline-start: 6px; }
.demo-ask { border: 0; padding: 0; background: none; font: inherit; color: var(--bl-blue); text-decoration: underline; cursor: pointer; }
/* 16px exactly: below it iOS zooms the page on focus; above it the address
   reads louder than the sentence it answers. */
.demo-row input { font-size: 1rem; }
.demo-row input::placeholder { color: var(--ink-3); opacity: 1; }
/* Stacked on a phone. `flex: 1` in a column container shrank the input to
   about 22px tall, with its text spilling out (founder, 10 Oct 2026), so the
   stacked input takes its own height and the full width, like the button. */
@media (max-width: 520px) {
  .demo-row { flex-direction: column; }
  .demo-row input { flex: none; width: 100%; height: 50px; }
  .demo-row .btn { width: 100%; min-height: 50px; }
}

/* --- "Last night, handled." (landing #stop): the inbox beside the rows ----- */
.receive.night { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 48px; align-items: start; margin-top: 52px; }
.receive.night .stop-rows { margin-top: 0; }
.night-inbox { margin: 0; }
.night-inbox .inbox { color: var(--ink); }
.night-inbox .inbox { border: 1px solid var(--card-line, var(--rule)); border-radius: var(--card-radius, 18px); overflow: hidden; background: var(--paper); }
.night-inbox .inbox-head { display: flex; justify-content: space-between; align-items: center; padding: 14px 18px; border-bottom: 1px solid var(--rule-soft); background: var(--paper-2); }
.night-inbox .inbox-head small { color: var(--ink-3); font-size: 0.8rem; }
.inbox-row { display: grid; grid-template-columns: 36px minmax(0, 1fr) auto; gap: 12px; padding: 14px 18px; border-bottom: 1px solid var(--rule-soft); align-items: start; }
.inbox-row:last-child { border-bottom: 0; }
.inbox-row b { display: block; font-size: 0.9rem; color: var(--ink); }
.inbox-row p { margin: 3px 0 0; font-size: 0.82rem; color: var(--ink-3); }
/* Each row's channel is Belline's own icon (src/components/ChannelMark.tsx,
   from the launcher), inlined as SVG with fill="currentColor" so the colour
   comes from a token here. Never a text badge like WA/CALL/WEB: the founder
   asked twice (10 Oct 2026). The span carries the name; the SVG is hidden. */
.ch { width: 36px; height: 36px; border-radius: 10px; display: grid; place-items: center; color: var(--bl-white); }
.ch svg { width: 20px; height: 20px; display: block; }
.ch-wa { background: var(--bl-whatsapp); } /* WhatsApp green: the WhatsApp mark only (CLAUDE.md) */
.ch-ph { background: var(--ink); }
.ch-web { background: var(--brass-fill); }
.tag { font-size: 0.7rem; font-weight: 600; border-radius: 999px; padding: 5px 10px; white-space: nowrap; }
.tag-req { background: var(--brass-soft); color: var(--brass); }
.tag-urg { background: var(--bl-warning-tint); color: var(--bl-warning-ink); }
.tag-ok { background: var(--bl-success-tint); color: var(--bl-success); }
.night-inbox figcaption { font-size: 0.78rem; color: var(--ink-3); margin-top: 10px; }
@media (max-width: 900px) { .receive.night { grid-template-columns: minmax(0, 1fr); } }
/* Inside the navy band, `#stop p` paints every paragraph pale for the dark
   ground; the inbox is a white card, so its own lines take the card's ink. */
#stop .night-inbox .inbox-row p { color: var(--bl-text-2); }
#stop .night-inbox figcaption { color: var(--bl-on-navy-2); }
/* The square now holds WhatsApp's own mark, not the letters "WA": a white
   handset on green, as WhatsApp draws it and as .wa-fab already does. Ink was
   for the words that used to sit here (white text on this green is under
   2:1); a mark is not text, and the founder asked for it white (10 Oct 2026). */
.ch-wa { color: var(--bl-whatsapp-mark); }
.foot-brand .foot-place { margin-top: 10px; font-size: 0.82rem; font-weight: 600; color: var(--ink-2); }

/* --- The cookie choice (public/consent.dca57ddb.js) ----------------------------------
   Two buttons of exactly the same size, weight and colour, because refusing
   must be as easy as accepting. Light, on the page's own ground, like
   everything else here.

   Where it stands is the whole difficulty, because whatever it stands on
   cannot be pressed until the visitor answers. The bottom-right corner belongs
   to Belle and her buttons. The bottom-left corner was the card's until the
   launch audit (15 Oct 2026) found it sitting exactly on "Start free for 7
   days" on a laptop, on Starter's button in the German pricing, on the phone
   menu's only "Get started", on /try's "Talk to Belle" and on Belle's face —
   and jumping 116px on a phone when her bubble arrived. So:

   - on a laptop it stands in the middle of the bottom edge, between the
     hero's words on the left and Belle's corner on the right;
   - on a phone it is a bar along the bottom, above the row of round
     buttons where they are drawn, the full width where Belle has stood them
     down, and painted there from the first frame (`video-pending` is in the
     markup of a page that expects her), so nothing moves when she arrives;
   - once she has landed in the corner it stands above her strip;
   - while the phone menu is open it is not drawn at all (site.js `nav-open`):
     the menu is the screen, and its "Get started" is under the card's place. */
.consent {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(24px + env(safe-area-inset-bottom, 0px));
  z-index: 45;
  /* 260px either side on the narrowest laptop: the hero's button on the left,
     Belle's landed strip and the round buttons on the right. */
  width: min(520px, calc(100vw - 520px));
  max-width: calc(100vw - 24px);
  margin-inline: auto;
  box-sizing: border-box;
  padding: 16px 20px;
  background: var(--bl-ground);
  color: var(--bl-ink-900);
  border: 1px solid var(--bl-rule-strong);
  border-radius: 14px;
  box-shadow: var(--site-shadow-call-dock);
  font-size: 0.88rem;
  line-height: 1.45;
  transition: bottom 0.2s ease;
}
.consent-text { margin: 0 0 12px; }
.consent-text a { color: var(--bl-accent-text); text-underline-offset: 3px; }
/* Wraps rather than overflows: "Nur notwendige" ran 31px off a phone's screen
   when the card was wider than the page. On one line or two, the two buttons
   are the same size (the same basis, the same growth). */
.consent-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.consent-btn {
  flex: 1 1 9em;
  min-height: 44px;
  padding: 10px 14px;
  font: inherit;
  font-weight: 500;
  color: var(--bl-ink-900);
  background: var(--bl-ground);
  border: 1px solid var(--bl-ink-900);
  border-radius: 999px;
  cursor: pointer;
}
.consent-btn:hover { background: var(--bl-surface); }
.consent-btn:focus-visible { outline: var(--bl-focus); outline-offset: var(--bl-focus-offset); }
.consent-btn[aria-pressed="true"] { background: var(--bl-blue-tint); }
/* Belle landed in the corner: her 96px face 24px from the bottom, her icons
   level with it, and a gap. */
body.has-video-bubble:has(.video-bubble[data-vb="corner"]) .consent {
  bottom: calc(136px + env(safe-area-inset-bottom, 0px));
}
body.nav-open .consent { display: none; }
@media (prefers-reduced-motion: reduce) {
  .consent { transition: none; }
}
/* The footer's "Cookie settings": an action, so a button, dressed as the
   footer's links beside it. */
.consent-open {
  padding: 0;
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
footer li .consent-open { text-decoration: none; }
footer li .consent-open:hover { text-decoration: underline; }
.consent-open:focus-visible { outline: var(--bl-focus); outline-offset: var(--bl-focus-offset); }
/* On a phone: a bar along the bottom edge, so the first screen's button, the
   menu and Belle's face are above it. Where the round buttons are drawn it
   stands just above their row (96px high, 16px from the edge, since 15 Oct
   2026 a row along the bottom rather than a column up the right side, so the
   bar takes the width above it instead of the width beside it). Buttons of
   44px, a finger's width (they were 40). */
@media (max-width: 900px) {
  .consent {
    left: 12px;
    right: 12px;
    bottom: calc(128px + env(safe-area-inset-bottom, 0px));
    width: auto;
    margin: 0;
    padding: 12px 14px;
    font-size: 0.8rem;
    line-height: 1.4;
  }
  .consent-text { margin-bottom: 10px; }
  .consent-actions { gap: 8px; }
  .consent-btn { flex-basis: 8em; min-height: 44px; padding: 8px 10px; }
  /* Where the round buttons stand down for Belle — before she arrives and
     while she is here, /try included — the bar takes the width. One rule for
     `video-pending` and `has-video-bubble`, because the card moving when one
     class gave way to the other was the 116px jump. */
  body.video-pending .consent,
  body.has-video-bubble .consent { right: 12px; }
  /* And with the row stood down, as low as it can go. */
  body.video-pending .consent,
  body.has-video-bubble .consent { bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }
  /* Her landed strip on a phone: the 96px face 16px from the bottom, her row
     of four beside it from the right edge to about a third of the way in
     (measured at 390x844 on 10 Oct 2026), and a gap. */
  body.has-video-bubble:has(.video-bubble[data-vb="corner"]) .consent {
    right: 12px;
    bottom: calc(128px + env(safe-area-inset-bottom, 0px));
  }
}
/* A phone on its side: 390px of height, and a card three lines tall sat on the
   headline. One line instead — the sentence beside the two buttons. */
@media (max-height: 500px) and (orientation: landscape) {
  .consent { display: flex; align-items: center; gap: 12px; padding: 8px 12px; font-size: 0.76rem; line-height: 1.35; }
  .consent-text { flex: 1 1 auto; margin: 0; }
  .consent-actions { flex: 0 0 auto; flex-wrap: nowrap; }
  .consent-btn { flex: 0 0 9.5em; }
}

/* --- /developers ------------------------------------------------------------
   The developer guide (scripts/site-developers.ts), laid out like the docs its
   readers compare it with: contents beside the text on a desktop, a short
   jump list above it on a phone. Light only, like the rest of the site.

   The code blocks scroll inside their own box instead of wrapping, unlike
   /docs/embed's: every one here has a Copy button, so nobody retypes a
   wrapped line, and a tag broken across three lines on a phone is harder to
   read than one that scrolls. The block for AI site builders is prose, and
   wraps. Nothing here may make the page itself scroll sideways at 375px. */
/* Two classes, so the room above and below survives `.wrap`'s padding
   shorthand wherever either rule is written (the same trap as `.top .top-in`). */
.wrap.dev-doc { max-width: 1220px; padding-top: 48px; padding-bottom: 96px; }
@media (max-width: 900px) { .wrap.dev-doc { padding-top: 28px; } }
.dev-intro, .dev-body { min-width: 0; max-width: 760px; }
.dev-body h2 { scroll-margin-top: 84px; }
.legal .dev-anchor {
  margin-inline-start: 10px;
  color: var(--ink-3);
  text-decoration: none;
  opacity: 0;
  transition: opacity 120ms;
}
.dev-body h2:hover .dev-anchor { opacity: 1; }

/* Contents. A phone gets it above the first section, as a compact box. */
.dev-toc {
  margin: 28px 0 8px;
  padding: 14px 16px;
  border: 1px solid var(--bl-rule);
  border-radius: 12px;
  background: var(--paper);
}
.legal .dev-toc-title {
  margin: 0 0 8px;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.dev-toc ol {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2px 12px;
}
.legal .dev-toc li { margin: 0; }
.legal .dev-toc a {
  display: flex;
  gap: 8px;
  align-items: baseline;
  padding: 5px 8px;
  border-radius: 6px;
  color: var(--ink-2);
  text-decoration: none;
  font-size: 0.9rem;
  line-height: 1.35;
}
.dev-toc-n { font-variant-numeric: tabular-nums; color: var(--ink-3); font-size: 0.8rem; min-width: 1ch; }
.legal .dev-toc a:hover { color: var(--ink); background: var(--bl-surface); }
.legal .dev-toc a[aria-current] { color: var(--bl-accent-text); background: var(--bl-blue-tint); font-weight: 600; }
.legal .dev-toc a[aria-current] .dev-toc-n { color: var(--bl-accent-text); }

@media (min-width: 1024px) {
  .dev-doc {
    display: grid;
    grid-template-columns: 210px minmax(0, 760px);
    grid-template-areas: "toc intro" "toc body";
    column-gap: 64px;
    align-items: start;
  }
  .dev-intro { grid-area: intro; }
  .dev-body { grid-area: body; }
  .dev-toc {
    grid-area: toc;
    position: sticky;
    top: 92px;
    margin: 8px 0 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
  }
  .dev-toc ol { grid-template-columns: 1fr; gap: 2px; border-inline-start: 1px solid var(--bl-rule); }
  .legal .dev-toc a { border-radius: 0 6px 6px 0; margin-inline-start: -1px; border-inline-start: 2px solid transparent; padding: 6px 10px; }
  .legal .dev-toc a[aria-current] { border-inline-start-color: var(--bl-blue); }
}
@media (max-width: 420px) {
  .dev-toc ol { grid-template-columns: minmax(0, 1fr); }
}

/* Code: a frame, a bar with the language and Copy (drawn by developers.js),
   and the block. The token colours are 4.5:1 or better on --bl-surface. */
.dev-code {
  margin: 14px 0 20px;
  border: 1px solid var(--bl-rule);
  border-radius: 10px;
  background: var(--bl-surface);
  overflow: hidden;
}
.dev-code-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 8px 6px 14px;
  border-bottom: 1px solid var(--bl-rule-soft);
  background: var(--paper);
}
.dev-code-lang { font-size: 0.72rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3); }
.dev-copy {
  font: 600 0.8rem/1 var(--bl-font-text);
  color: var(--bl-accent-text);
  background: var(--paper);
  border: 1px solid var(--bl-blue-line);
  border-radius: 6px;
  padding: 7px 12px;
  min-height: 30px;
  cursor: pointer;
}
.dev-copy:hover { border-color: var(--bl-blue); }
.dev-copy.is-done { color: var(--ink); border-color: var(--bl-rule-strong); }
.legal .dev-code pre {
  margin: 0;
  padding: 14px 16px;
  border: 0;
  border-radius: 0;
  background: none;
  overflow-x: auto;
}
.legal .dev-code pre code { white-space: pre; overflow-wrap: normal; color: var(--ink); }
.legal .dev-code-text pre code { white-space: pre-wrap; overflow-wrap: anywhere; }
.tk-tag, .tk-fn { color: var(--bl-accent-text); }
.tk-attr, .tk-kw { color: var(--bl-code-name); }
.tk-str { color: var(--bl-code-value); }
.tk-com { color: var(--ink-3); font-style: italic; }

/* Tables: names in monospace (they are <code>), zebra rows, and on a phone
   each row becomes a card with the column's name over each value. */
.legal .dev-table { border: 1px solid var(--bl-rule); border-radius: 10px; }
.legal .dev-table table { min-width: 0; }
.legal .dev-table th { background: var(--bl-surface); padding: 10px 14px; font-size: 0.82rem; }
.legal .dev-table td { padding: 10px 14px; }
.legal .dev-table tbody tr:nth-child(even) td { background: var(--bl-row-alt); }
.legal .dev-table tbody tr:last-child td { border-bottom: 0; }
.legal .dev-table td:first-child code { white-space: nowrap; color: var(--ink); font-weight: 600; }
@media (max-width: 700px) {
  .legal .dev-table { border: 0; overflow: visible; }
  .legal .dev-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .legal .dev-table table, .legal .dev-table tbody, .legal .dev-table tr, .legal .dev-table td { display: block; width: 100%; }
  .legal .dev-table tr { border: 1px solid var(--bl-rule); border-radius: 10px; margin-bottom: 12px; overflow: hidden; }
  .legal .dev-table td, .legal .dev-table tbody tr:nth-child(even) td { background: none; border-bottom: 1px solid var(--bl-rule-soft); padding: 8px 14px; }
  .legal .dev-table td:first-child { background: var(--bl-surface); }
  .legal .dev-table tbody tr td:last-child { border-bottom: 0; }
  .legal .dev-table td::before {
    content: attr(data-label);
    display: block;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-3);
    margin-bottom: 2px;
  }
}

/* Try it: drawn only by developers.js, which also writes its line. */
.dev-try {
  margin: 22px 0 26px;
  padding: 18px 18px 6px;
  border: 1px solid var(--bl-blue-line);
  border-radius: 12px;
  background: var(--paper);
}
.dev-try[hidden] { display: none; }
.legal .dev-try-title { margin: 0 0 4px; font-size: 1.05rem; }
.legal .dev-try-lead { margin: 0 0 14px; font-size: 0.92rem; }
.dev-try-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; align-items: start; }
@media (max-width: 700px) { .dev-try-grid { grid-template-columns: minmax(0, 1fr); } }
.dev-try-controls { display: grid; gap: 14px; min-width: 0; }
.dev-seg { border: 0; margin: 0; padding: 0; min-width: 0; }
.dev-seg legend, .dev-range label { font-size: 0.82rem; font-weight: 600; color: var(--ink); padding: 0; margin-bottom: 6px; }
.dev-seg-row { display: flex; flex-wrap: wrap; gap: 6px; }
.dev-seg label { position: relative; }
.dev-seg input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.dev-seg span {
  display: inline-block;
  padding: 6px 12px;
  border: 1px solid var(--bl-blue-line);
  border-radius: 999px;
  font: 500 0.84rem/1.2 ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  color: var(--ink-2);
  background: var(--paper);
}
.dev-seg input:checked + span { background: var(--bl-blue); border-color: var(--bl-blue); color: var(--bl-white); }
.dev-seg input:focus-visible + span { outline: var(--bl-focus); outline-offset: var(--bl-focus-offset); }
.dev-range-top { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.dev-range output { font: 500 0.84rem/1 ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; color: var(--ink); }
.dev-range input[type="range"] { width: 100%; accent-color: var(--bl-blue); margin: 4px 0 2px; }
.legal .dev-range-attr { font-size: 0.75rem; color: var(--ink-3); background: none; padding: 0; }
.dev-range[hidden], .dev-try-note[hidden] { display: none; }
.legal .dev-try-note { font-size: 0.84rem; color: var(--ink-3); margin: 0 0 12px; }
.dev-try-fig { margin: 0; min-width: 0; }
.dev-screen {
  position: relative;
  aspect-ratio: 16 / 10;
  border: 1px solid var(--bl-rule-strong);
  border-radius: 8px;
  background: linear-gradient(var(--bl-surface), var(--bl-surface)) top / 100% 14px no-repeat, var(--paper);
  overflow: hidden;
}
.dev-dot {
  position: absolute;
  border-radius: 50%;
  background: var(--bl-blue);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
  transition: left 120ms, right 120ms, bottom 120ms, width 120ms, height 120ms;
}
.legal .dev-try-fig figcaption { margin-top: 8px; font-size: 0.8rem; color: var(--ink-3); }
.dev-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; margin: 0; }
@media (prefers-reduced-motion: reduce) { .dev-dot, .legal .dev-anchor { transition: none; } }

/* ===========================================================================
   One header, one footer, one rhythm on every page (founder review, 14 Oct
   2026). scripts/site-chrome.ts `siteHeader` writes the header; these rules
   are the parts of it the old pages never had.
   ======================================================================== */

/* The legal pages, /partners, /developers and /docs/embed are `.wrap.legal`.
   `.legal` asked for 72px above and 96px below, and the `.wrap` rule written
   2,000 lines later reset both with its `padding` shorthand — so the heading
   sat against the header and "Apply by email" against the footer ("too close
   to the menu … too close to the footer", founder). Two classes win on
   specificity wherever either rule is written, the same fix as `.top .top-in`. */
.wrap.legal { padding-top: 72px; padding-bottom: 104px; }
@media (max-width: 900px) {
  .wrap.legal { padding-top: 44px; padding-bottom: 80px; }
}
/* The 404's hero and the docs' own block keep their own rhythm. */
.wrap.legal.dev-doc { padding-top: 56px; padding-bottom: 104px; }

/* "Sign in", a button you can see: bordered, beside the main one, rather than
   a line of grey text after it ("kind of hidden and not very user
   friendly"). Lighter than "Get started", which stays the one filled button. */
.top nav .nav-quiet {
  padding: 10px 18px;
  border: 1px solid var(--bl-rule-strong);
  border-radius: var(--bl-radius-pill);
  font-weight: var(--bl-weight-button);
  color: var(--bl-ink-900);
  white-space: nowrap;
}
.top nav .nav-quiet:hover { border-color: var(--bl-ink-900); color: var(--bl-ink-900); }

/* On a phone the menu is folded away, so the main action waits in the bar
   itself, beside the menu button: "Start free trial", filled, the page's one primary
   button. It was "Sign in" until the launch audit (15 Oct 2026) found no way
   to start anywhere in a phone's first screen; scripts/site-chrome.ts
   `siteHeader` has the whole reason. "Sign in" is a row of the menu now. */
.top-cta { display: none; }
@media (max-width: 900px) {
  .top-cta {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    margin-inline-start: auto;
    padding: 0 16px;
    border-radius: var(--bl-radius-pill);
    background: var(--bl-blue);
    color: var(--bl-white);
    font-size: 0.92rem;
    font-weight: var(--bl-weight-button);
    text-decoration: none;
    white-space: nowrap;
  }
  .top-cta:hover { background: var(--bl-blue-hover); color: var(--bl-white); }
  .top-cta:focus-visible { outline: var(--bl-focus); outline-offset: var(--bl-focus-offset); }
  .top-cta + .menu-toggle { margin-inline-start: 8px; }
  /* "Sign in" in the open menu: a plain row like the links above it, not the
     bordered pill the desktop bar draws (the rule just above this block,
     which would otherwise win here by coming later in the file). */
  .top nav .nav-quiet {
    display: block;
    padding: 17px 0;
    border: 0;
    border-bottom: 1px solid var(--rule-soft);
    border-radius: 0;
    font-family: var(--bl-font-text);
    font-size: 1rem;
    font-weight: 400;
    white-space: normal;
  }
}
/* The narrowest phones (320px, an iPhone SE): the button keeps its words and
   the bar gives up the air around it instead. */
@media (max-width: 360px) {
  .top .top-in { gap: 10px; }
  .top-cta { padding: 0 12px; font-size: 0.86rem; }
  .top-cta + .menu-toggle { margin-inline-start: 6px; flex-shrink: 0; }
  /* "Start free trial" and "Kostenlos testen" are wider than the room the
     wordmark leaves at 320px, and the menu button was squeezed to a sliver.
     The bell mark stays and the name is still read out; only the drawn word
     gives way, and only on these few phones. */
  .top-in.cta-long .brand span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* The country and language picker, upgraded by site.js: a compact panel of
   two native selects (founder, f31, 14 Oct 2026: the full-screen sheet of
   twelve rows was "not user-friendly", "a dropdown would be better"). On a
   desktop the panel drops from the button; in the phone menu the selects
   stand in the menu itself and the button is not drawn, because the menu is
   already the panel and a second tap in front of the phone's own picker is
   one tap too many. Without JavaScript the <details> of links above still
   opens, as it always did. */
.locale.is-select > .locale-panel {
  width: 300px;
  padding: 16px;
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
  max-height: none;
  overflow: visible;
}
.locale-fields { display: grid; gap: 14px; }
.locale-field label {
  display: block;
  margin: 0 0 6px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bl-muted);
}
.locale-row { display: flex; gap: 8px; }
.locale-pick { position: relative; flex: 1; min-width: 0; display: block; }
.locale-pick::after {
  content: "";
  position: absolute;
  inset-inline-end: 15px;
  top: 50%;
  width: 6px;
  height: 6px;
  margin-top: -5px;
  border-right: 1.6px solid var(--bl-ink-900);
  border-bottom: 1.6px solid var(--bl-ink-900);
  transform: rotate(45deg);
  pointer-events: none;
}
.locale-field select {
  width: 100%;
  height: 44px;
  padding-block: 0;
  padding-inline: 12px 34px;
  border: 1px solid var(--bl-rule-strong);
  border-radius: 10px;
  background: var(--bl-ground);
  color: var(--bl-ink-900);
  font-family: var(--bl-font-text);
  /* 16px: below it iOS zooms the page in when the select is tapped. */
  font-size: 1rem;
  font-weight: 500;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}
.locale-field select:hover { border-color: var(--bl-ink-900); }
.locale-field select:focus-visible { outline: 2px solid var(--bl-blue); outline-offset: 2px; }
.locale-go {
  flex: none;
  height: 44px;
  padding: 0 16px;
  border: 0;
  border-radius: 10px;
  background: var(--bl-blue);
  color: var(--bl-text-inverted);
  font: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
}
.locale-go[hidden] { display: none; }
.locale-go:focus-visible { outline: 2px solid var(--bl-blue); outline-offset: 2px; }
@media (max-width: 900px) {
  .top nav .locale.is-select { margin-top: 18px; }
  .top nav .locale.is-select > .locale-btn { display: none; }
  .top nav .locale.is-select > .locale-panel,
  .top nav .locale.is-select > .locale-panel[hidden] {
    display: block !important;
    position: static;
    width: auto;
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
    box-shadow: none;
  }
}

/* The calendar pill on a phone: one line, like the pills around it ("the
   bullet becomes double line and it looks out of line", founder, 14 Oct
   2026). The words are the founder's shorter ones (site-flags.ts `canEvery`);
   between 400px and a tablet they are set a touch smaller rather than broken.
   Below 400px the short form takes over, as before. */
@media (max-width: 900px) {
  .hero-demo .hero-can li.can-cal { white-space: nowrap; font-size: min(0.84rem, 3.05vw); }
}
/* A phone's first screen: four claims at most, and "Start free" above Belle.

   The launch audit (15 Oct 2026) found the hero's button below the fold on
   every phone it measured (y 676–726 on a 664px screen) behind eight pills,
   "tap to talk" and her face. Two things give.

   The channel pills go on a phone, because the line under the headline
   already names every one of them from the same flags (site-flags.ts
   `applyHeroChannels` and the hero-sub beside it): "Your AI receptionist for
   phone, WhatsApp, Instagram and your website." followed by Phone, WhatsApp,
   Instagram and Website as pills is the same sentence twice, and the second
   copy is a whole row of the first screen. What stays is what the sentence
   does not say: answers, enquiries, the calendar and the tools — four at most.

   And the calendar claim takes its short form on every phone, not only beside
   Belle. The long one ("Books into Google & Apple Calendar, Outlook or
   Calendly", longer still in German) is wider than a 390px column even at
   3.05vw, and with `nowrap` above it pushed the page sideways. */
@media (max-width: 600px) {
  .hero-can .can-ch,
  .hero-can .can-break,
  .hero-demo.has-video-hero .hero-can .can-break { display: none; }
}
@media (max-width: 520px) {
  .hero-can .cal-long,
  .hero-demo.has-video-hero .hero-can .cal-long { display: none; }
  .hero-can .cal-short,
  .hero-demo.has-video-hero .hero-can .cal-short { display: inline; }
}
/* With Belle in the hero, on a phone: the button, then her. She used to come
   first and the button after her face and her icons, which put it under the
   fold; above her it is in the first screen and she is still the largest thing
   in it. The note on `.hero-demo.has-video-hero` in "Site review" has the rest
   of this order. */
@media (max-width: 900px) {
  .hero-demo.has-video-hero .cta-row { order: 1; margin-top: 18px; }
  .hero-demo.has-video-hero .hero-video { order: 2; margin-top: 4px; }
}
/* A short phone (375x667), where e2e video holds her icons inside the first
   screen with every claim live: the button is a finger's height rather than
   49px and the air around it is the least that still reads as a gap. The rest
   came from her circle (234, in the short-phone block of "Site review"). */
@media (max-width: 520px) and (max-height: 720px) {
  .hero-demo.has-video-hero .cta-row { margin-top: 6px; }
  .hero-demo.has-video-hero .cta-row .btn { min-height: 44px; padding-block: 11px; }
  .hero-demo.has-video-hero .hero-video { margin-top: 0; }
}

/* --- Arabic, right to left (/ar-ae) ------------------------------------------
   The page is public/landing.ar.html, <html lang="ar-AE" dir="rtl">. Most of
   the mirroring is already done above: margins, paddings, borders and the
   decorative bullets are written as logical properties (inline-start/end), so
   they follow the page's direction and read exactly as before on the
   left-to-right pages. Flex rows and grids mirror by themselves.

   What stays physical, on purpose: the floating contact buttons, Belle's
   video bubble and the call and chat docks keep the right-hand corner they
   have on every other page. They are drawn by embed-video.js and embed.js on
   customers' sites too, and one corner for Belle everywhere is a smaller
   surprise than a corner that changes with the language. */

/* One Arabic face for every word, with the Latin faces after it so "Belline"
   or "Google Calendar" inside an Arabic sentence still sets in Plex. The
   stylesheet that loads it (fonts.googleapis.com) is the one every landing
   page already loads; no new host. */
html[lang^="ar"] {
  --bl-font-text: "IBM Plex Sans Arabic", "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Tahoma, Arial, sans-serif;
  --bl-font-display: "IBM Plex Sans Arabic", "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Tahoma, Arial, sans-serif;
  --serif: var(--bl-font-display);
}
html[lang^="ar"] body { font-family: var(--bl-font-text); }

/* Arabic letters join. Any tracking, positive or negative, pulls the joins
   apart or crushes them, so on an Arabic page nothing is tracked. */
html[lang^="ar"] *,
html[lang^="ar"] *::before,
html[lang^="ar"] *::after { letter-spacing: 0 !important; }

/* Arabic needs more room between lines than Latin: the dots above and below
   the letters collide at the tight leading the English headlines use. */
html[lang^="ar"] .display { line-height: 1.32; }
html[lang^="ar"] .lead,
html[lang^="ar"] .sec-lead { line-height: 1.75; }

/* An arrow that means "onward" points the way the page reads. */
[dir="rtl"] .dir-icon { transform: scaleX(-1); }

/* The footer's column headings are spaced capitals in English; Arabic has no
   capitals, and spacing its letters breaks the joins between them. */
[dir="rtl"] .foot-cols h4 { letter-spacing: 0; text-transform: none; }

/* Numbers typed into the calculator are read left to right, like every
   number on the page. */
[dir="rtl"] .roi-field input { direction: ltr; text-align: center; }

/* The site's own floating buttons, the chat and call docks and the cookie
   card change sides with the page: on /ar-ae the hero's words are on the
   right, and buttons in the right-hand corner sat on top of its call to
   action (measured at 1280 on 14 Oct 2026). Belle's bubble is drawn by
   embed-video.js, the same file customers' sites load, and keeps its corner;
   while she is on the page these buttons stand down anyway. */
/* The row of round buttons mirrors with the page: its flex row runs right to
   left under dir="rtl", so Belle's face is at its left end, in the corner. */
[dir="rtl"] .fabs { right: auto; left: 20px; }
[dir="rtl"] :is(.chat-dock, .call-dock) { right: auto; left: 26px; }
[dir="rtl"] .call-shut { right: auto; left: -10px; }
/* (On a laptop the cookie card stands in the middle of the bottom edge, which
   is the middle in either direction.) */
@media (max-width: 900px) {
  [dir="rtl"] .fabs { left: 16px; }
  [dir="rtl"] .call-dock { left: 16px; right: 16px; }
  [dir="rtl"] .consent { left: 12px; right: 12px; }
  [dir="rtl"] body.video-pending .consent,
  [dir="rtl"] body.has-video-bubble .consent { left: 12px; right: 12px; }
}
/* On a phone the chat is a sheet across the whole width, in either direction. */
@media (max-width: 620px) {
  [dir="rtl"] .chat-dock { left: 0; right: 0; }
}

/* --- Pricing, round 2 (15 Oct 2026): "Every plan includes" as a strip above
   the cards, "Everything in Starter, plus:" as the head of a card's list, one
   comparison table, and the "Keep your number" block. All generated
   (scripts/site-pricing.ts); the strip keeps the `plan-shared` markup the
   server writes the calendar and tools lines into. */
#price .plan-shared { margin: 0 0 20px; padding: 14px 20px; display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 18px; }
#price .plan-shared-h { margin: 0; font-size: 0.92rem; white-space: nowrap; }
#price .plan-shared ul { columns: auto; display: flex; flex-wrap: wrap; gap: 6px 20px; }
#price .plan-shared li { padding-block: 0; }
#price .plan-diff li.plan-plus { padding-inline-start: 0; font-weight: 600; color: var(--bl-ink-900); }
#price .plan-diff li.plan-plus::before { display: none; }

.cmp { margin-top: 40px; }
.cmp-h { margin: 0 0 14px; font-family: var(--bl-font-display); font-weight: var(--bl-weight-heading); font-size: 1.15rem; color: var(--bl-ink-900); }
.cmp-scroll { overflow-x: auto; border: 1px solid var(--card-line); border-radius: var(--card-radius); background: var(--bl-ground); }
.cmp-scroll:focus-visible { outline: 2px solid var(--bl-blue); outline-offset: 2px; }
.cmp-table { width: 100%; min-width: 520px; border-collapse: collapse; font-size: 0.88rem; }
.cmp-table th,
.cmp-table td { padding: 11px 16px; text-align: center; border-bottom: 1px solid var(--rule-soft); color: var(--bl-text-2); }
.cmp-table tbody tr:last-child th,
.cmp-table tbody tr:last-child td { border-bottom: 0; }
.cmp-table thead th { font-family: var(--bl-font-display); font-weight: var(--bl-weight-heading); color: var(--bl-ink-900); font-size: 0.95rem; }
.cmp-table thead th.is-best { color: var(--bl-blue); }
.cmp-table th[scope="row"] { text-align: start; font-weight: 400; color: var(--bl-ink-900); position: sticky; inset-inline-start: 0; background: var(--bl-ground); min-width: 180px; }
.cmp-table .cmp-price td { font-weight: 600; color: var(--bl-ink-900); }
.cmp-table .cmp-yes { color: var(--bl-blue); font-weight: 600; }
.cmp-table .cmp-no { color: var(--bl-rule-strong); }
/* On a phone the three plans fit beside the labels, rather than scrolling out of sight. */
@media (max-width: 620px) {
  .cmp-table { min-width: 0; font-size: 0.8rem; table-layout: fixed; }
  .cmp-table th, .cmp-table td { padding: 9px 4px; }
  .cmp-table th[scope="row"] { min-width: 0; width: 42%; padding-inline-start: 12px; position: static; }
  .cmp-table thead th { font-size: 0.8rem; }
  .cmp-table thead td { width: 42%; }
}
#price .plan-shared li::before { top: 0.55em; }

.keep-number .terms { margin-top: 32px; }
.keep-number .terms p + p { margin-top: 8px; }
/* "Tell me when the phone opens in {country}" under an on-request phone card
   (site-flags.ts `phoneAskForm`, founder 15 Oct 2026). Email and button on one
   line where they fit, stacked on a phone. The field is 16px, not 15: iPhone
   zooms the page into any field under 16px (PR 380, r2-speed). */
.phone-ask { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.phone-ask input[type="email"] { flex: 1 1 180px; min-width: 0; font: inherit; font-size: 16px; padding: 8px 12px; border: 1px solid var(--rule); border-radius: 10px; background: var(--paper); color: var(--ink); }
.phone-ask .btn { flex: 0 1 auto; white-space: normal; text-align: left; }
.phone-ask-note { flex-basis: 100%; margin: 0; font-size: 14px; }
.phone-ask-note:empty { display: none; }
.phone-ask-note.is-bad { color: var(--bl-danger); }
