/* ==========================================================================
   Nota — design tokens and styles.
   Brand system: Nota blue-teal, midnight ink, and the Québec signal.
   Deviation from Tablix on purpose: squared corners (Tablix uses rounded-xl).
   All colors are tokens — no literal color values below the :root blocks.
   ========================================================================== */

/* ==========================================================================
   Les polices, servies par Nota — jamais par un tiers.
   Inter (texte) et Sora (titres) arrivaient de fonts.googleapis.com : l'adresse
   IP et l'agent de CHAQUE visiteur atteignaient Google avant toute bannière, sur
   un site qui vend des actes notariés (propriétaire, 2026-09-12). Les octets
   vivent désormais dans /fonts, licence OFL jointe (fonts/OFL.txt).
   Ce sont les versions VARIABLES : un seul fichier par tranche couvre toutes
   les graisses. `swap` garde le texte lisible pendant le chargement.
   ========================================================================== */
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url('/fonts/inter-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url('/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Sora'; font-style: normal; font-weight: 100 800; font-display: swap;
  src: url('/fonts/sora-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Sora'; font-style: normal; font-weight: 100 800; font-display: swap;
  src: url('/fonts/sora-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }


:root {
  /* Nota blue ramp: institutional cobalt for trust and rigor, with a
     restrained light blue for digital interactions. */
  --nota-blue-50: #ebf1f5;
  --nota-blue-100: #e5eef3;
  --nota-blue-200: #c8dbe3;
  --nota-blue-300: #a7c1cd;
  --nota-blue-400: #78a9bf;
  --nota-blue-500: #407598;
  --nota-blue-600: #386888;
  --nota-blue-700: #386888;
  --nota-blue-800: #274a62;
  --nota-blue-900: #264961;
  --nota-blue-950: #101b26;
  /* Warm Nota accent: use the dark value for text on light surfaces and the
     brighter value on midnight surfaces so the orange remains readable. */
  --nota-orange-600: #b45309;
  --nota-orange-400: #f79009;
  --accent-warm: var(--nota-orange-600);
  /* Vibrant accent colors — purple, blue, orange that catch the eye across all pages. */
  --accent-purple: #a855f7;
  --accent-blue: #6366f1;
  --accent-sky: #0ea5e9;
  /* Channel-only copies of the three steps that alpha tokens below need
     (shadows, focus glow, background wash). rgb() cannot take a hex var, so
     these exist so no ramp value is ever retyped as a literal downstream. */
  --nota-blue-400-rgb: 120 169 191;
  --nota-blue-500-rgb: 64 117 152;
  --nota-blue-700-rgb: 56 104 136;

  /* Semantic tokens (light) */
  --brand: var(--nota-blue-700);
  /* Couleurs de MARQUE des fournisseurs tiers (portes à venir). Ce sont des
     constantes appartenant à Google, Meta et LinkedIn : elles ne suivent pas
     le thème et ne se redéfinissent nulle part — mais elles restent des
     jetons nommés plutôt que des littéraux dispersés dans les règles. */
  --marque-google-chip: var(--paper); /* le « G » doit rester sur fond blanc */
  --marque-youtube: #ff0000;
  --marque-facebook: #1877f2;
  --marque-linkedin: #0a66c2;
  --brand-bright: var(--nota-blue-500);
  --brand-ink: var(--paper);
  --brand-hover: var(--nota-blue-800);
  --on-accent: var(--paper); /* text/knob on saturated accents (tier pills, toggle) — white in every theme */

  /* The LIGHT canvas, named once. Two blocks need these exact values: the
     light theme itself, and the print block far below, which has to restate a
     light canvas because both dark blocks outrank :root on paper. Naming them
     here means the print block aliases instead of retyping — a light value
     exists in exactly one place (ADR 0048). */
  --canvas-bg: #eef5f7;
  --canvas-surface: #fbfdfd;
  --canvas-surface-inset: #e6f0f4;
  --canvas-surface-hover: #dcecf2;
  --canvas-ink: #173b52;
  --canvas-ink-muted: #526b78; /* was #607986: 4.49:1 on the surface, 3.79 on the canvas — under AA for the 12–15px muted text it colours; #526b78 clears 4.6 everywhere (2026-09-11) */
  --canvas-subtitle-ink: #000000;
  --canvas-border: #c5d8df;
  --canvas-border-strong: #a9c3ce;
  --paper: #ffffff; /* true white — printed paper, and the ink on a brand fill */

  --bg: var(--canvas-bg);
  --surface: var(--canvas-surface);
  --surface-inset: var(--canvas-surface-inset);
  --surface-hover: var(--canvas-surface-hover);
  --ink: var(--canvas-ink);
  --ink-muted: var(--canvas-ink-muted);
  --subtitle-ink: var(--canvas-subtitle-ink);
  --border: var(--canvas-border);
  --border-strong: var(--canvas-border-strong);
  --ring: var(--nota-blue-600);

  --footer-heart: #e53e3e; /* Decorative Québec credit, shared across themes. */
  --danger: #b42318;
  --warn: var(--accent-warm);
  --ok: var(--nota-blue-600);
  --danger-solid: #b42318; /* solid deep red for badge fills — dark --danger is a light salmon that fails white-text contrast */
  /* The tint pair (owner, 2026-08-27: « components carry no opacity — the
     background does »): --brand-tint keeps its alpha and is RESERVED for the
     background layers (the body's top fade, --wash-glow, the intro film),
     where translucency lets the drifting marks live. --brand-tint-solid is
     the SAME wash mixed down to the surface — fully opaque — and is what
     components (chips, badges, step discs, hover fills) paint with, so
     nothing ever bleeds through a component. Auto-follows each theme:
     the mix resolves against that theme's --brand-bright / --surface. */
  --brand-tint: rgb(var(--nota-blue-500-rgb) / 0.05); /* faint brand wash — background layers only */
  --brand-tint-mix: 6%;
  --brand-tint-solid: color-mix(in srgb, var(--brand-bright) var(--brand-tint-mix), var(--surface));
  /* The HIGHLIGHT tint: one step richer than the component wash, for the one
     card a pane singles out (the notaire reward). Own mix, because the dark
     themes need a much deeper pour — at the component mix the highlight
     reads as washed grey on near-black, not as brand. */
  --brand-tint-mix-strong: 12%;
  --brand-tint-solid-strong: color-mix(in srgb, var(--brand-bright) var(--brand-tint-mix-strong), var(--surface));
  /* The ink the highlight card writes with. On light the deep --brand clears
     AA over the strong tint; on dark it does not (the tint is a POUR of the
     accent, so ink and ground converge), so the dark themes step up to the
     accent itself. One token, so the rules that write on the strong tint
     never have to know which theme they are in. */
  --brand-on-tint-strong: var(--brand);
  /* L'encre d'un ÉTAT VIVANT — un onglet retenu, une ligne de marché survolée,
     la carte d'acte choisie. Sur papier, c'est la marque elle-même. Sur fond de
     nuit, --brand (#407598) est plus SOMBRE que l'encre : le libellé tombait à
     2,5–3,3:1 — il s'ÉTEIGNAIT au moment même où le doigt le désigne
     (propriétaire, 2026-09-12 : « le hover sur le financement… quel acte ? »).
     Les thèmes sombres montent donc d'un barreau, exactement comme
     --brand-on-tint-strong juste au-dessus. Aucune règle d'état ne repasse par
     --brand nu dans un `color:` — contraste-etats.test.mjs le refuse. */
  --brand-on-surface: var(--brand);
  /* L'encre du MOT « OTA » du lockup. Elle vivait dans une règle tardive
     (.brand-word { color: var(--brand-hover) }) qui battait sans le dire la
     règle de base 6 500 lignes plus haut, et le film d'accueil — canevas
     CLAIR même quand la page est en nuit — héritait alors d'un bleu de nuit
     posé sur du blanc. Un jeton, une seule règle.
     LE MOT EST DE L'ENCRE (propriétaire, 2026-09-12 : « the brand nota make
     the font white ») : blanc sur la nuit, noir sur le jour — le registre
     d'encre des titres vaut aussi pour la marque. Le bleu ne reste que sur ce
     qui SIGNALE : le carré du sceau et le point final du mot. */
  --brand-word-ink: var(--ink);
  /* The earlier 95 % skin (owner, 2026-08-27: « blanc c'est très beau… mais on
     pourrait mettre un tout petit peu d'opacité, genre quatre-vingt-quinze
     pour cent » — superseding the earlier 90 %) — the shared translucent
     surface for the LARGE landing panels (calendar, reward cards, gate
     cards), always paired with a backdrop blur so what bleeds through
     reads as light, not marks. Small controls (buttons, chips, inputs) and
     anything stacked (dialogs, dropdowns, sticky header) stay fully opaque.
     An alias like --brand-tint-solid: auto-follows each theme's --surface. */
  /* 2026-09-12: lighter panels, with text opacity preserved at 100%. */
  --surface-veil-mix: 84%;
  --surface-veil: color-mix(in srgb, var(--surface) var(--surface-veil-mix), transparent);
  /* The hover wash at the same register — for rows that light up OVER a
     veiled panel (the landing's market rows): an opaque hover card over a
     translucent panel read as a pasted-on sticker (owner: « le hover sur le
     financement est bizarre »). Auto-follows each theme's --surface-hover. */
  --surface-soft-veil: color-mix(in srgb, var(--surface) 58%, transparent);
  --panel-border: color-mix(in srgb, var(--border) 70%, transparent);
  /* THE MOTION REGISTER. Every transition and animation that is interface
     FEEDBACK reads one of these three rungs and --ease-ui; no UI rule sets its
     own duration or its own curve. Before 2026-09-14 the tokens existed and
     were used seven times against 139 hand-set durations and 34 ad hoc
     bezier curves, so nothing in the product moved on a shared rhythm.
       --motion-fast   hover, colour, focus, small state flips
       --motion-ui     panels, dialogs, pane entry
       --motion-enter  the larger arrivals
     The exception, deliberately left literal: scene-setting motion that is not
     feedback — the film's slow gradient drifts (igLightDrift 26s, igOrbit),
     attention flashes, the button spinner. Those are measured in seconds and
     belong to no UI rung; tokenising them would invite someone to later
     "harmonise" a 26s ambient drift with a 150ms hover. */
  --motion-fast: 150ms;
  --motion-ui: 220ms;
  --motion-enter: 320ms;
  /* Arrival cursor animation: deliberate, guided pacing — each scene breathes
     so the eye can register what the cursor is pointing at before it moves on. */
  --arrival-start: 500ms;
  --arrival-travel: 700ms;
  --arrival-scene: 2500ms;
  --ease-ui: cubic-bezier(.22, 1, .36, 1);
  /* Le ressort. UNE seule courbe de dépassement, et elle est nommée : le point
     de contrôle 1.56 fait passer la transformation AU-DELÀ de sa cible avant de
     revenir. Réservée à ce qui se pose (la graine de voix, l'orbe qui écoute) —
     jamais à une couleur, jamais à une opacité, qui n'ont pas de « au-delà ».
     Tout le reste lit --ease-ui (guide §6.3 principe 2). */
  --ease-spring: cubic-bezier(.34, 1.56, .64, 1);
  /* Menu entrance stagger — each drawer row arrives 40ms after the one above,
     so the panel fills top-to-bottom instead of appearing as a block. */
  --menu-stagger: 40ms;
  /* Drawer-item arrival: a quiet slide + fade, timed to --motion-ui. */
  --menu-item-dur: var(--motion-ui);
  /* Hamburger ↔ ✕ morph: three lines translate to centre then rotate. */
  --burger-dur: var(--motion-ui);
  --surface-hover-veil: color-mix(in srgb, var(--surface-hover) var(--surface-veil-mix), transparent);

  /* Tier accent ramp — cool (calm) to warm (urgent).
     All five are dark enough for white .pill text to meet WCAG AA (>=4.5:1). */
  --tier-standard: #64748b;
  --tier-rapide: #356c87;
  --tier-prioritaire: #906800;
  --tier-urgence: #c2410c;
  --tier-extreme: #b42318;
  /* Outline text/border tint per tier — light = base, dark = brighter for AA
     (the dark values live in BOTH dark blocks below; keep all three in sync).
     Rapide is the CALM baseline and covers most of a month's cells, so its ink
     is NEUTRAL (owner, 2026-08-28, twice: « trop vert ») — the cell's tier bar
     and the legend dot keep the blue; the saturated ramp starts at urgency. */
  --tier-rapide-ink: var(--ink-muted); --tier-prioritaire-ink: var(--tier-prioritaire);
  --tier-urgence-ink: var(--tier-urgence); --tier-extreme-ink: var(--tier-extreme);

  /* Per-service categorical hues — deliberately distinct from the blue brand
     and the blue→red tier ramp; used only as calendar data-viz fills (the
     per-service mix bar + its legend). TWO acts of the financing family
     (ADR 0010): each act owns its token here, and every theme block below
     redefines BOTH — a service colour must never fall back to a light value
     in the dark themes. */
  --svc-refinancement: #0ea5e9; /* vibrant sky blue — strong on light surfaces */
  --svc-financement: #6366f1; /* vibrant indigo — clearly apart from the teal sibling */
  --svc-testament: #f59e0b; /* vibrant amber — warm and eye-catching */
  --svc-procuration: #a855f7; /* vibrant purple — distinct and bold */

  /* Offer status: waiting for a notary vs. retained by one. var() aliases, so
     they track the theme automatically — do not duplicate into the dark blocks. */
  --status-ouverte: var(--brand-bright);
  --status-retenue: var(--ink-muted);

  /* Geometry — ONE square scale for every shape (owner's ask, 2026-08-27:
     « tout garder le même style carré »). No pills, no circles: controls and
     chips take --radius, badges and knobs --radius-sm, thin bars --radius-xs.
     Pure signal DOTS (≤8px, border-radius:50%) are the only round survivors —
     a dot is punctuation, not a component. */
  --radius: 8px;
  --radius-sm: 6px;
  --radius-xs: 3px;
  --radius-lg: 12px;

  color-scheme: light;
  --shadow-sm: 0 1px 2px rgb(16 27 38 / .04), 0 4px 12px -8px rgb(16 27 38 / .12);
  --shadow: 0 2px 6px -3px rgb(16 27 38 / .07), 0 16px 36px -20px rgb(16 27 38 / .2);
  --shadow-lg: 0 24px 50px -16px rgb(var(--nota-blue-700-rgb) / 0.24);
  --shadow-brand: 0 6px 18px -8px rgb(var(--nota-blue-700-rgb) / .24); /* brand-primary hover lift */
  --logo-shadow: 0 1px 2px rgb(16 27 38 / 0.15);       /* header brand mark */
  --focus-ring: rgb(var(--nota-blue-500-rgb) / 0.3);      /* brand focus glow (3px) */
  --backdrop: rgb(16 27 38 / 0.12);                    /* light dialog scrim keeps the page readable */
  --backdrop-soft: rgb(16 27 38 / 0.08);               /* the tour's light scrim — it guides, it does not seal the page */

  --font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, 'SF Mono', 'JetBrains Mono', Menlo, monospace;
  /* The wordmark uses a custom monoline SVG, so every letter stays aligned at
     every size. Sora is the display face of EVERY heading — owner, 2026-09-10:
     the Signature beta page is the reference and the whole app follows it. */
  --font-display: 'Sora', var(--font-sans);
  --weight-display: 800;
  /* --- Type scale: quieter headings, comfortable running text -----------
     One register for the whole app. No heading rule sets its own size, face
     or weight — it reads a step of this scale (typographie.test.mjs enforces
     it), so the three doors, the dialogs and the beta print one voice. */
  --type-h1: clamp(26px, 2.25vw, 36px); --type-h1-lh: 1.12; --type-h1-ls: -.04em;
  --type-h1-compact: clamp(26px, 6vw, 32px); /* the stacked (narrow) hero */
  --type-h2: clamp(19px, 1.5vw, 24px); --type-h2-lh: 1.2; --type-h2-ls: -.035em;
  --type-h3: 17px; --type-h3-lh: 1.3; --type-h3-ls: -.02em;
  --type-h4: 15px; --type-h4-lh: 1.3; --type-h4-ls: -.01em; /* dense card kickers (.nc-h, .nc-live-h, .nc-conformite-h) — ADR 0050, addendum 2026-09-11 */
  --type-lead: 16px; --type-lead-lh: 1.6;
  --type-eyebrow: 12px; --type-eyebrow-ls: .1em;
  /* Body register (owner, 2026-09-11: « every font size the same across ALL
     applications »): the running-text size and leading, named so the brand
     guide, the pitch deck and the business plan read the SAME step instead of
     15 / 16.5 / browser-default. Mirrored verbatim in tokens.css,
     signature.css, brand.html, pitch-deck.html, business-plan.html
     (typographie.test.mjs compares every copy). */
  --type-body: 16px; --type-body-lh: 1.5;

  --layout-width: 2200px;
  --layout-gutter: clamp(16px, 4vw, 40px);
  --maxw: var(--layout-width); /* maximized width — unified rail from brand-foundations */
  --gap: 20px;
  /* Spacing scale. These are the values already most used in this file, named
     so neighbouring components stop drifting 1-3px apart. */
  --space-1: 2px;  --space-2: 4px;   --space-3: 6px;   --space-4: 8px;
  --space-5: 10px; --space-6: 12px;  --space-7: 14px;  --space-8: 16px;
  --space-9: 18px; --space-10: 20px; --space-12: 24px; --space-14: 28px;
  --space-16: 32px;
  /* The intro's responsive breathing room, shared with anything that must
     top-align with the intro's first line (e.g. the notary sign-in card). */
  --intro-pad-top: clamp(16px, 1.8vw, 24px);
  /* Ambient gradients (owner, 2026-08-27, superseding the morning's
     « gradient on every component »: « the gradient and the opacity are for
     the REST, not the component themselves »). Atmosphere lives ONLY on the
     background layers — the body's top fade, --wash-glow behind sections,
     the #site-bg drift. Components are flat, fully opaque surfaces
     (--surface / --surface-inset / --brand-tint-solid): their contrast
     never shifts with what sits beneath, and nothing bleeds through. */
  /* Each glow must reach full transparency BEFORE every edge of the box it
     paints (nearest-edge distance / radius >= the fade stop on all four
     sides), otherwise the box boundary slices the light and draws the very
     edge this token exists to avoid. */
  --wash-glow:
    radial-gradient(38% 52% at 72% 38%, var(--brand-tint) 26%, transparent 72%),
    radial-gradient(30% 52% at 22% 62%, var(--brand-tint) 26%, transparent 72%);
  /* The three decisions everything else derives from. */
  --pad-card: var(--space-6) var(--space-7);
  --pad-card-lg: var(--space-8) var(--space-9);
  --pad-dialog: var(--space-12);

  --header-h: 64px;   /* The dark brand band has room for the full lockup. */
  --sticky-top: 84px; /* header height + breathing gap — used for scroll-padding / scroll-margin */
  --header-bg: var(--nota-blue-950);
  --header-ink: #f4f8fa;
  --header-muted: var(--nota-blue-200);
  --header-border: var(--nota-blue-800);
  --header-badge-bg: var(--nota-blue-100);
  --header-badge-ink: var(--nota-blue-950);

  /* Fixed third-party brand-mark colours (Google / Outlook calendar logos).
     These are brand IDENTITY constants, NOT theme tokens: they must render
     identically in every theme and must never be restyled. Defined here only so
     no literal colour lives in markup — reference via var() in the SVG fills. */
  /* --- Surfaces that stay dark in EVERY theme ------------------------------
     The signing room (ADR 0047) and the video frames are a dark room by
     design: they do not flip with the theme, so they cannot read --ink / --bg
     / --danger-solid, which do. The roles they need are named ONCE here, with
     the dark theme's own values, rather than retyped as literals in the rules
     below (ADR 0048: a one-off hex in a component rule is a defect). */
  --midnight-ink: #f4f8fa;                    /* = the dark theme's --ink */
  --midnight-matte: #000000;                  /* letterbox behind a video frame */
  --midnight-veil-soft: rgb(255 255 255 / 0.04);   /* block fill on the rail */
  --midnight-veil: rgb(255 255 255 / 0.06);        /* quiet button fill */
  --midnight-veil-strong: rgb(255 255 255 / 0.12); /* its hover */
  --sheen: rgb(255 255 255 / 0.34);           /* inset top highlight on a raised panel */
  --danger-solid-rgb: 180 35 24;              /* channels of --danger-solid, for alpha washes */
  --danger-wash: rgb(var(--danger-solid-rgb) / 0.18); /* alert ground on a midnight surface */
  --danger-pale: #ffe4e1;                     /* the ink that reads on --danger-wash */
  --on-warn: #1b1300;                         /* ink on an --accent-warm fill */

  --logo-google-blue: #4285f4;
  --logo-google-green: #34a853;
  --logo-google-yellow: #fbbc05;
  --logo-google-red: #ea4335;
  --logo-outlook-blue: #0f6cbd;
  --logo-microsoft-red: #f25022;
  --logo-microsoft-green: #7fba00;
  --logo-microsoft-blue: #00a4ef;
  --logo-microsoft-yellow: #ffb900;
  --logo-on-brand: var(--paper);
}

/* Dark theme — system preference.
   A STANDALONE @media block: prefers-color-scheme now actually applies. The old
   form comma-joined a selector list to an @media rule (`:root[...], @media {...}`),
   which is invalid CSS and was silently discarded — so system-dark users got the
   light UI. Excludes an explicit light opt-out via :not([data-theme='light']). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --brand: var(--nota-blue-500);
    --brand-bright: var(--nota-blue-400);
    --brand-ink: #061c2a;
    --brand-hover: var(--nota-blue-400);
    --accent-warm: var(--nota-orange-400);

    /* A blue foundation, softened (owner, 2026-09-14: « keep a blue
       foundation, but softer and less intense »). This supersedes the
       neutral-graphite note that stood here: the canvas now carries a blue
       cast, but at the graphite's luminance, so blue reads as the ground
       without flooding it at full intensity. */
    --bg: #14181d;
    --surface: #1b2026;
    --surface-inset: #222830;
    --surface-hover: #29313a;
    --ink: #f4f8fa;
    --ink-muted: #afc2cf;
    --subtitle-ink: #f4f8fa;
    --border: #37424e;
    --border-strong: #536273;
    --ring: var(--nota-blue-400);

    --danger: #f97066;
    --warn: var(--accent-warm);
    --ok: var(--nota-blue-500);
    --danger-solid: #b42318;
    --brand-tint: rgb(255 255 255 / 0.025);
    --brand-tint-mix: 8%;
    --brand-tint-mix-strong: 20%; /* deep pour: on near-black a component-level mix greys out — but 26 % pushed --brand ink on the highlight card below AA, so the card now carries --brand-on-tint-strong instead */
    --brand-on-tint-strong: var(--brand-bright);
    --brand-on-surface: var(--brand-bright); /* l’encre des états vivants : un barreau plus clair, sinon le libellé s’éteint au moment où on le désigne */
    --brand-word-ink: var(--ink); /* le mot du lockup est blanc sur la nuit : de l'encre, jamais du bleu */
    --backdrop: rgb(3 7 9 / 0.52);
    --backdrop-soft: rgb(3 7 9 / 0.38);

    --tier-standard: #64748b;
    --tier-rapide: #356c87;
    --tier-prioritaire: #906800;
    --tier-urgence: #c2410c;
    --tier-extreme: #b42318;
    --tier-rapide-ink: var(--ink-muted); /* NEUTRAL — the green cast was too much (owner, 2026-08-28) */ --tier-prioritaire-ink: #e0b44a; --tier-urgence-ink: #f0894c; --tier-extreme-ink: #f97066;
    --svc-refinancement: #78a9bf;
    --svc-financement: #818cf8;
    --svc-testament: var(--nota-orange-400);
    --svc-procuration: #c4a7ff;
    --accent-purple: #c4a7ff;
    --accent-blue: #818cf8;
    --accent-sky: #78a9bf;

    /* Dark shadows are cast in black, not light ink, so they read on #0a0a0a. */
    --shadow-sm: 0 1px 2px rgb(0 0 0 / .2), 0 4px 12px -8px rgb(0 0 0 / .3);
    --shadow: 0 2px 6px -3px rgb(0 0 0 / .2), 0 16px 36px -20px rgb(0 0 0 / .5);
    --shadow-lg: 0 20px 40px -12px rgb(0 0 0 / 0.6);
    --shadow-brand: 0 6px 18px -8px rgb(0 0 0 / .4);
    --focus-ring: rgb(var(--nota-blue-400-rgb) / 0.45);
    color-scheme: dark;
  }
}

/* Explicit dark toggle — wins over system preference in both directions.
   Defines the SAME complete token set as the @media block above; keep the two in
   lockstep so no token (e.g. --warn, --shadow-lg) drifts back to its light value. */
:root[data-theme='dark'] {
  --brand: var(--nota-blue-500);
  --brand-bright: var(--nota-blue-400);
  --brand-ink: #061c2a;
  --brand-hover: var(--nota-blue-400);
  --accent-warm: var(--nota-orange-400);

  /* A blue foundation, softened (owner, 2026-09-14: « keep a blue
     foundation, but softer and less intense »). This supersedes the
     neutral-graphite note that stood here: the canvas now carries a blue
     cast, but at the graphite's luminance, so blue reads as the ground
     without flooding it at full intensity. */
  --bg: #14181d;
  --surface: #1b2026;
  --surface-inset: #222830;
  --surface-hover: #29313a;
  --ink: #f4f8fa;
  --ink-muted: #afc2cf;
  --subtitle-ink: #f4f8fa;
  --border: #37424e;
  --border-strong: #536273;
  --ring: var(--nota-blue-400);

  --danger: #f97066;
  --warn: var(--accent-warm);
  --ok: var(--nota-blue-500);
  --danger-solid: #b42318;
  --brand-tint: rgb(255 255 255 / 0.025);
  --brand-tint-mix: 8%;
  --brand-tint-mix-strong: 20%; /* deep pour: on near-black a component-level mix greys out — but 26 % pushed --brand ink on the highlight card below AA, so the card now carries --brand-on-tint-strong instead */
  --brand-on-tint-strong: var(--brand-bright);
  --brand-on-surface: var(--brand-bright); /* l’encre des états vivants : un barreau plus clair, sinon le libellé s’éteint au moment où on le désigne */
  --brand-word-ink: var(--ink); /* le mot du lockup est blanc sur la nuit : de l'encre, jamais du bleu */
  --backdrop: rgb(3 7 9 / 0.52);
  --backdrop-soft: rgb(3 7 9 / 0.38);

  --tier-standard: #64748b;
  --tier-rapide: #356c87;
  --tier-prioritaire: #906800;
  --tier-urgence: #c2410c;
  --tier-extreme: #b42318;
  --tier-rapide-ink: var(--ink-muted); /* NEUTRAL — the green cast was too much (owner, 2026-08-28) */ --tier-prioritaire-ink: #e0b44a; --tier-urgence-ink: #f0894c; --tier-extreme-ink: #f97066;
  --svc-refinancement: #78a9bf;
  --svc-financement: #818cf8;
  --svc-testament: var(--nota-orange-400);
  --svc-procuration: #c4a7ff;
  --accent-purple: #c4a7ff;
  --accent-blue: #818cf8;
  --accent-sky: #78a9bf;

  /* Dark shadows are cast in black, not light ink, so they read on #0a0a0a. */
  --shadow-sm: 0 1px 2px rgb(0 0 0 / .2), 0 4px 12px -8px rgb(0 0 0 / .3);
  --shadow: 0 2px 6px -3px rgb(0 0 0 / .2), 0 16px 36px -20px rgb(0 0 0 / .5);
  --shadow-lg: 0 20px 40px -12px rgb(0 0 0 / 0.6);
  --shadow-brand: 0 6px 18px -8px rgb(0 0 0 / .4);
  --focus-ring: rgb(var(--nota-blue-400-rgb) / 0.45);
  color-scheme: dark;
}

/* Interaction colors describe the action, while service colors keep their
   data meaning. Derive ink and opaque tints in each scope so both themes keep
   readable text; labels, borders and focus outlines also express the state. */
:root {
  --action-accent: var(--accent-blue);
  --action-ink-mix: 60%;
  --action-surface: var(--surface);
  --action-text: var(--ink);
  --accent-gold: var(--tier-prioritaire-ink);
  --help-control-size: 56px;
  --help-edge-gap: 24px;
  --help-fill: var(--brand);
  --help-hover: color-mix(in srgb, var(--brand) 85%, #fff);
}
:root, .tab-pane, dialog, .site-header, .nav-tab, .mnav-link, .header-tools,
.header-voice-btn, .experience-path, .speed-dial, .speed-dial-option,
.pulse-row, .chip-svc {
  --action-ink: color-mix(in srgb, var(--action-accent) var(--action-ink-mix), var(--action-text));
  --action-tint: color-mix(in srgb, var(--action-accent) 12%, var(--action-surface));
  --action-tint-strong: color-mix(in srgb, var(--action-accent) 20%, var(--action-surface));
  --ring: var(--action-ink);
  --focus-ring: color-mix(in srgb, var(--action-accent) 32%, transparent);
}
#pane-notaires, [data-tab='notaires'], .experience-path--notary,
.header-voice-btn, #sd-voice { --action-accent: var(--accent-purple); }
#pane-partenaires, [data-tab='partenaires'], .speed-dial, #sd-guide {
  --action-accent: var(--brand);
  --action-ink-mix: 40%;
}
#pane-beta, [data-tab='beta'], #sd-chat { --action-accent: var(--accent-blue); }
[data-svc='refinancement'] { --action-accent: var(--svc-refinancement); }
[data-svc='financement'] { --action-accent: var(--svc-financement); }
[data-svc='testament'] { --action-accent: var(--svc-testament); --action-ink-mix: 40%; }
[data-svc='procuration'] { --action-accent: var(--svc-procuration); }
.site-header {
  --action-surface: var(--header-bg);
  --action-text: var(--header-ink);
  --control-surface: color-mix(in srgb, var(--header-ink) 12%, var(--header-bg));
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
/* Selected text answers to the brand, not to the browser's default blue —
     which read as a foreign UI on a dark Nota page and lost contrast on
   the light one. Both halves are stated (never colour alone on a veil). */
::selection { background: color-mix(in srgb, var(--brand) 30%, transparent); color: var(--ink); }

body {
  margin: 0;
  /* Sticky-footer column: without it the footer sits wherever the content ends
     and the rest of the viewport is bare canvas — 412px on Notaires, 784px on
     Profil. dvh (with a vh fallback) so mobile browser chrome does not add a
     phantom scrollbar. */
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  font-family: var(--font-sans);
  font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11';
  /* The page's ambient light: a full-width fade bleeding down from the top
     edge, over the flat token — every pane opens under it. 180deg only: a
     centred radial pooled in the middle of a wide screen and left the
     margins flat black (owner: « clash with black margin »). */
  background: linear-gradient(180deg, var(--brand-tint), transparent 460px) no-repeat, var(--bg);
  color: var(--ink);
  font-size: var(--type-body);
  line-height: var(--type-body-lh);
  -webkit-font-smoothing: antialiased;
  transition: background-color var(--motion-ui) var(--ease-ui), color var(--motion-ui) var(--ease-ui);
}

/* Takes the slack in the body column, so the footer is pushed to the bottom on
   short pages and simply follows the content on long ones. The bottom padding
   keeps every pane's last card off the footer rule. */
#main { flex: 1 0 auto; padding-bottom: var(--space-14); }

/* Every heading is display type on the shared scale; a pane only colours it. */
h1, h2, h3 { font-family: var(--font-display); font-weight: var(--weight-display); margin: 0; }
h1 { font-size: var(--type-h1); line-height: var(--type-h1-lh); letter-spacing: var(--type-h1-ls); text-wrap: balance; }
h2 { font-size: var(--type-h2); line-height: var(--type-h2-lh); letter-spacing: var(--type-h2-ls); }
h3 { font-size: var(--type-h3); line-height: var(--type-h3-lh); letter-spacing: var(--type-h3-ls); }

a { color: var(--action-ink); text-decoration: none; }
a:hover { text-decoration: underline; }

.wrap { max-width: var(--layout-width); margin-inline: auto; padding: 0 var(--layout-gutter); }

/* --- Skip link ----------------------------------------------------------- */
.skip {
  position: absolute; left: -999px; top: 0;
  background: var(--brand); color: var(--brand-ink);
  padding: 10px 16px; z-index: 100; border-radius: 0 0 var(--radius) 0;
}
.skip:focus { left: 0; }
/* The hidden SVG symbol table (the logomark): zero-size, out of flow, never read. */
.svg-defs { position: absolute; width: 0; height: 0; overflow: hidden; }

/* --- Header -------------------------------------------------------------- */
.site-header {
  /* The menu is its OWN layer above the page (owner, 2026-08-27: « a bigger
     diff in between menu and body ») — and a SOLID one (same day, later:
     « components carry no opacity — the background does »): opaque surface
     plus a real shadow carry the separation. The former glass tone + blur
     let the page smear through the bar; WCAG-wise a translucent chrome's
     contrast shifts with whatever scrolls beneath — solid never does.
     Distinct without ever drawing a hairline. */
  background: var(--header-bg);
  box-shadow: var(--shadow);
  position: sticky; top: 0; z-index: 40;
}
.site-header .wrap {
  display: flex; align-items: center; gap: 12px;
  height: var(--header-h);
  position: relative;
}
.site-header :is(.icon-btn, .header-auth .btn, .header-tools) {
  color: var(--header-muted);
}
.site-header .nav-tab-badge { color: var(--header-muted); }
.site-header .icon-btn { border-color: var(--header-border); }
.site-header .icon-btn:is(:hover, :focus-visible) { background: var(--control-surface); color: var(--header-ink); border-color: var(--header-muted); }
.site-header .header-tools {
  --action-accent: var(--header-ink);
  /* The existing controls inherit one header palette. Their tracks remain
     unfilled; selection and hover share the same solid surface. */
  --surface-inset: transparent;
  --surface: var(--control-surface);
  --surface-hover: var(--control-surface);
  --ink: var(--header-ink);
  --ink-muted: var(--header-muted);
  --brand: var(--header-ink);
  --brand-on-surface: var(--header-ink);
  --border: var(--header-border);
}
/* The lockup's geometry (ADR 0048, 2026-09-11: design 02 « Signal repris par
   le badge », optical sizing at 50%): FIVE custom properties, declared
   ONCE on every lockup root. A surface sets --lockup-tile alone; the word's
   cap height, the two gaps and the badge follow as ratios of the tile, and the
   word is centred on the tile. The wordmark symbol's viewBox is its cap band,
   so a word box --lockup-word tall renders caps exactly that tall.
   signature.css and admin.css declare the same five with the same ratios —
   ux-nav.test.mjs (P2-19) keeps the three in lockstep. */
.brand, .footer-brand{
  --lockup-tile: 36px;
  --lockup-word: calc(var(--lockup-tile) * .48);
  --lockup-gap: calc(var(--lockup-tile) * .12);
  --lockup-badge-gap: calc(var(--lockup-tile) * .24);
  --lockup-badge-size: max(8px, calc(var(--lockup-tile) * .135)); /* Québec is a location signal: smaller than the wordmark, with room to breathe beside it. */
}
.brand {
  display: flex; align-items: center; gap: var(--lockup-badge-gap);
  font-weight: 800; font-size: 18px; letter-spacing: -0.03em; color: var(--header-ink);
  border: 0; background: transparent; box-shadow: none; padding: 0;
}
.brand:hover { text-decoration: none; }
.brand-lockup {
  display: inline-flex; align-items: center; gap: var(--lockup-gap); flex: none;
  color: var(--brand); line-height: 1;
}
.brand-mark-svg { display: block; width: var(--lockup-tile, 28px); height: var(--lockup-tile, 28px); flex: none; transition: transform var(--motion-fast) var(--ease-ui); }
.brand-word { display: inline-flex; align-items: center; width: calc(var(--lockup-word) * 91.8 / 28); height: var(--lockup-word); color: var(--brand-word-ink); line-height: 1; }
.brand-word-svg { display: block; width: 100%; height: 100%; overflow: visible; }
/* La valeur de repli n'est pas de la décoration : --lockup-tile n'est posé
   que par .brand-lockup, et une marque placée AILLEURS (l'en-tête du tiroir)
   voyait sa largeur devenir invalide, donc `auto` — 162 px de logo sur un
   téléphone de 375 (capture du propriétaire, 2026-09-12). */
.brand-mark { width: var(--lockup-tile, 28px); height: var(--lockup-tile, 28px); display: grid; place-items: center; }
.brand-mark img { display: block; width: 100%; height: 100%; filter: drop-shadow(var(--logo-shadow)); }
/* Québec is a location signal, not a footnote: keep it readable in both themes. */
.brand-sub {
  display: inline-flex; align-items: center; flex: none; white-space: nowrap;
  color: var(--header-badge-ink); font-weight: 600; font-size: var(--lockup-badge-size); text-transform: uppercase;
  letter-spacing: .1em; padding: .3em .42em; background: var(--header-badge-bg); border-radius: var(--radius-xs);
}
.result-count { font-size: 12px; font-weight: 600; color: var(--ink-muted); white-space: nowrap; }
/* Next-availability cue in the calendar toolbar — a live blue dot + soonest
   open date, so the carnet reads as active at a glance. */
.cal-avail { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 600; color: var(--ink); white-space: nowrap; padding: 4px 11px; border: 1px solid var(--border); border-radius: var(--radius); }
.cal-avail::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--brand); flex: none; }
/* The captured partner code is visible only on this visitor's device. */
.referral-status { width: 100%; box-sizing: border-box; padding-top: 12px; padding-bottom: 0; flex: 0 0 auto; }
.referral-status[hidden] { display: none; }
.referral-status-card { display: flex; align-items: center; gap: 12px; padding: 12px 16px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.referral-status-check { display: grid; place-items: center; width: 32px; height: 32px; flex: none; border-radius: 50%; color: var(--brand); background: var(--surface-inset); }
.referral-status-copy { display: grid; gap: 3px; flex: 1; min-width: 0; font-size: 13px; line-height: 1.45; }
.referral-status-copy > span { color: var(--ink-muted); }
.referral-status-card .btn { min-height: 44px; flex: none; }
@media (max-width: 540px) {
  .referral-status-card { flex-wrap: wrap; gap: 8px; }
  .referral-status-copy { flex-basis: calc(100% - 44px); }
  .referral-status-card .btn { margin-left: 40px; }
}
.book-referral { margin: 12px 0; }

.header-spacer { flex: 1; }

/* flex:none — the tab strip never shrinks below its labels: a squeezed header
   must slim its paddings (compact band below), never wrap a label to two lines.
   The four public doors stay flat, with no submenu layer. */
.nav-tabs { display: flex; gap: 2px; flex: none; position: relative; }
.nav-tab {
  appearance: none; border: 1px solid transparent; background: transparent;
  color: var(--header-muted); font: inherit; font-weight: 600; font-size: 13.5px;
  padding: 6px 11px; border-radius: var(--radius); cursor: pointer;
  display: inline-flex; align-items: center; gap: 8px;
  white-space: nowrap;
  position: relative;
  transition: background-color var(--motion-fast) var(--ease-ui), color var(--motion-fast) var(--ease-ui), border-color var(--motion-fast) var(--ease-ui), transform var(--motion-fast) var(--ease-ui);
}
.nav-tab-icon { flex: none; color: currentColor; transition: transform var(--motion-fast) var(--ease-ui); }
.nav-tab-badge {
  flex: none; margin-left: 1px; padding: 2px 5px;
  border: 1px solid currentColor; border-radius: var(--radius-xs);
  color: var(--accent-purple); font-size: 9px; font-weight: 800;
  letter-spacing: .06em; line-height: 1; text-transform: uppercase;
}
.nav-tab:is(:hover, :focus-visible) { background: var(--action-tint); color: var(--action-ink); border-color: var(--action-ink); }
.nav-tab:hover .nav-tab-icon { transform: translateY(-1px); }
.nav-tab[aria-selected='true'] {
  background: var(--action-tint-strong); color: var(--action-ink);
  border-color: var(--action-ink);
}
/* The active door carries a 2px accent line anchored to the bottom edge —
   it slides under the selected tab as the single moving identifier. */
.nav-tab[aria-selected='true']::after {
  content: ''; position: absolute; bottom: -1px; left: 50%; width: 60%;
  height: 2px; background: var(--header-badge-bg); border-radius: var(--radius-xs);
  transform: translateX(-50%);
  animation: navIndicator var(--motion-ui) var(--ease-ui) both;
}
/* Keep navigation in normal layout so language, voice and account controls
   always reserve their real width instead of covering an absolute tab row. */
/* Header compact band: between the drawer threshold (900) and a roomy desktop
   (1280) the full control set fits by slimming chrome: tighter gaps and paddings,
   and the QUÉBEC pill steps aside. Labels never wrap (nowrap above); this band
   is what guarantees they also never overflow. */
@media (min-width: 900px) and (max-width: 1279.98px) {
  .site-header .wrap { gap: 8px; padding-inline: 16px; }
  .brand-sub { display: none; }
  /* The tab GLYPHS step aside with the QUÉBEC pill. The band was measured in
     English, where the same controls need exactly 900px; French needs 1002 —
     « Espace notaire », « Partenaires », « Se connecter », « S'inscrire » —
     so from 900 to 1001 the signup button was painted past the right edge and
     clipped by `overflow-x: clip`, with no sideways scroll to reach it. Four
     icons and their gaps are 92px; the LABELS are what a door is, and they all
     stay. (e2e/french-fits.spec.js measures the fit in both languages.) */
  .nav-tab-icon { display: none; }
  .nav-tab { padding: 6px 8px; }
  .header-auth .btn { padding-left: 9px; padding-right: 9px; }
  /* The tool strip tightens with the band: narrower gaps and FR/EN cells
     (the hairlines re-centre themselves from --tools-gap). */
  .header-tools { --tools-gap: 8px; }
  .header-tools .mini-seg-btn { padding: 0 6px; }
  .header-voice-label { display: none; }
  .header-voice-btn { min-width: 44px; min-height: 44px; justify-content: center; }
}

.icon-btn {
  appearance: none; font: inherit; border: 1px solid var(--border-strong); background: transparent;
  color: var(--ink); width: 34px; height: 34px; border-radius: var(--radius);
  cursor: pointer; display: grid; place-items: center; font-size: 16px;
  transition: background-color var(--motion-fast), color var(--motion-fast), border-color var(--motion-fast);
}
.icon-btn:hover { background: transparent; border-color: var(--action-ink); }
.icon-btn[aria-pressed='true'] { background: transparent; color: var(--action-ink); border-color: var(--action-ink); }
.icon-btn svg { display: block; }
.icon-btn:active { transform: scale(0.94); }
/* Language, theme and voice share one unfilled rail. The local header palette
   gives selected controls a consistent surface without nested background boxes. */
.header-tools {
  --tools-gap: 12px;
  display: inline-flex; align-items: center; gap: var(--tools-gap); flex: none;
  padding: 2px 4px; border-radius: var(--radius); background: var(--surface-inset);
}
.header-tools > * { position: relative; }
.header-tools > * + *::after {
  content: ''; position: absolute; top: 6px; bottom: 6px;
  left: calc(var(--tools-gap) / -2 - 0.5px); width: 1px; background: var(--border);
}
/* Small FR | EN segment: BOTH options stay visible and the current one sits
   raised on a filled pill — the state reads at a glance, where the old single
   button showed only the OTHER language. Active marking and clicks are wired
   by NotaI18N.wireToggles(). Used in the header strip and the drawer's
   preference rows; 28px tall everywhere, matching the "?" and the switch. */
.mini-seg {
  display: inline-flex; align-items: center; gap: 2px; flex: none;
  height: 28px; padding: 2px; border-radius: var(--radius); background: var(--surface-inset);
}
.mini-seg-btn {
  appearance: none; display: inline-flex; align-items: center; justify-content: center;
  height: 24px; padding: 0 9px; border: 1px solid transparent; background: transparent;
  color: var(--ink-muted); font: inherit; font-size: 11.5px; font-weight: 700;
  letter-spacing: 0.04em; line-height: 1; border-radius: var(--radius-sm);
  cursor: pointer; transition: background var(--motion-fast), color var(--motion-fast);
}
.mini-seg-btn:hover { color: var(--ink); }
.mini-seg-btn[aria-pressed='true'] {
  background: var(--surface); color: var(--action-ink);
  border-color: var(--border); box-shadow: var(--shadow-sm);
}

/* Theme switch: a small sun/moon track whose knob covers the CURRENT side
   (checked = dark). The knob and icon tint follow html[data-theme] so the
   control is right from the first paint — before app.js boots; app.js then
   mirrors the state onto aria-checked (header + drawer twins) for AT.
   Geometry: 28 = 2px pad + 24px cell + 2px pad; two 24px icon cells; the
   24px knob slides one cell over. */
.tswitch {
  appearance: none; font: inherit; position: relative; display: inline-flex; align-items: center;
  justify-content: space-between; flex: none; width: 52px; height: 28px; padding: 2px;
  border: 0; border-radius: var(--radius);
  background: var(--surface-inset); color: var(--ink-muted); cursor: pointer;
}
.tswitch svg { position: relative; z-index: 1; display: block; flex: none; margin: 0 5.5px; }
.tswitch::before {
  content: ''; position: absolute; top: 2px; left: 2px; z-index: 0;
  width: 24px; height: 24px; border-radius: var(--radius-sm);
  background: var(--surface); border: 1px solid var(--border);
  box-shadow: var(--shadow-sm); transition: transform var(--motion-fast) var(--ease-ui);
}
:root[data-theme='dark'] .tswitch::before { transform: translateX(24px); }
:root[data-theme='dark'] .tswitch .tswitch-moon,
:root:not([data-theme='dark']) .tswitch .tswitch-sun { color: var(--brand); }

/* Voice stays directly reachable in the shared header. It opens the assistant
   for supported navigation and page controls; confirmation remains visible in
   the relevant screen. Its hover surface follows language and theme. */
.header-voice-btn {
  appearance: none; display: inline-flex; align-items: center; gap: 6px;
  height: 28px; padding: 0 10px; border: 1px solid transparent;
  border-radius: var(--radius-sm); background: transparent;
  color: var(--ink-muted); font: inherit; font-size: 12px; font-weight: 600;
  cursor: pointer; transition: background var(--motion-fast), color var(--motion-fast), border-color var(--motion-fast);
}
.header-voice-btn:is(:hover, :focus-visible) {
  background: var(--action-tint); color: var(--action-ink); border-color: var(--action-ink);
}
.header-voice-btn:focus-visible {
  outline: 2px solid var(--ring); outline-offset: 2px;
}
.header-voice-btn svg { flex: none; }
.header-voice-label { line-height: 1; }

/* --- Notifications (bell + dropdown, paired with the email the API sends) -- */
.notif-wrap { position: relative; }
#notif-bell { position: relative; }
#notif-bell.has-unread { color: var(--brand); }
.notif-badge {
  position: absolute; top: -5px; right: -5px; min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: var(--radius-sm); background: var(--danger-solid); color: var(--on-accent);
  font-size: 10px; font-weight: 800; line-height: 17px; text-align: center;
  border: 2px solid var(--surface);
}
.notif-panel {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  width: min(340px, calc(100vw - 32px));
  background: var(--surface); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  overflow: hidden; animation: paneIn var(--motion-fast) var(--ease-ui) both;
}
.notif-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 12px 14px; border-bottom: 1px solid var(--border);
}
.notif-head-title { font-weight: 700; font-size: 13px; }
.notif-list { max-height: min(420px, 70vh); overflow-y: auto; overscroll-behavior: contain; }
.notif-empty { padding: 24px 14px; text-align: center; color: var(--ink-muted); font-size: 13px; }
.notif-item {
  position: relative; padding: 11px 34px 11px 14px; border-bottom: 1px solid var(--border); cursor: default;
  transition: background-color var(--motion-fast);
}
/* Per-item dismiss — a quiet ✕ that firms up on hover/focus, sized like the
   calendar's cell chevron so small round actions stay one family. */
.notif-x {
  position: absolute; top: 8px; right: 6px; display: grid; place-items: center;
  width: 24px; height: 24px; padding: 0; appearance: none; border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--ink-muted); font-size: 11px; line-height: 1; cursor: pointer;
}
.notif-x:hover { background: var(--action-tint); color: var(--ink); }
.notif-x:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; }
.notif-item:last-child { border-bottom: 0; }
.notif-item[role='button'] { cursor: pointer; }
.notif-item[role='button']:hover { background: var(--action-tint); }
.notif-item[role='button']:focus-visible { background: var(--action-tint); outline: 2px solid var(--ring); outline-offset: -2px; }
.notif-item.is-unread { background: var(--surface-hover); }
.notif-item.is-unread .notif-title::before {
  content: ''; display: inline-block; width: 7px; height: 7px; margin-right: 7px;
  border-radius: 50%; background: var(--brand); vertical-align: middle;
}
.notif-title { font-size: 13px; font-weight: 600; color: var(--ink); }
.notif-body { font-size: 12px; color: var(--ink-muted); margin-top: 2px; }

/* Account menu (avatar) — merges profile + notifications + menu into one panel. */
.acct-btn { border-radius: var(--radius); border: 1px solid var(--border); }
.acct-btn:hover { border-color: var(--action-ink); }
.acct-btn[aria-expanded='true'] { border-color: var(--action-ink); color: var(--action-ink); }
.acct-panel {
  padding: 8px;
  animation: acctPanelIn var(--motion-ui) var(--ease-ui) both;
}
@keyframes acctPanelIn { from { opacity: 0; transform: translateY(4px) scale(.98); } to { opacity: 1; transform: none; } }
.acct-panel-head { display: flex; align-items: flex-start; gap: 2px; padding: 2px 2px 6px; }
.acct-panel-head .acct-head { flex: 1; min-width: 0; }
.acct-close { flex: none; color: var(--ink-muted); }
.acct-close:hover { color: var(--ink); }
.acct-item {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  appearance: none; background: transparent; border: 0; border-radius: var(--radius);
  padding: 9px 10px; font: inherit; color: var(--ink); cursor: pointer;
  animation: acctItemIn var(--motion-fast) var(--ease-ui) both;
}
@keyframes acctItemIn { from { opacity: 0; transform: translateX(-4px); } to { opacity: 1; transform: none; } }
.acct-action:nth-child(1) { animation-delay: 40ms; }
.acct-action:nth-child(2) { animation-delay: 80ms; }
.acct-action:nth-child(3) { animation-delay: 120ms; }
.acct-action:nth-child(4) { animation-delay: 160ms; }
.acct-item:hover { background: var(--action-tint); }
.acct-item:focus-visible { background: var(--action-tint); outline: 2px solid var(--ring); outline-offset: -2px; }
.acct-item svg { flex: none; color: var(--ink-muted); }
.acct-avatar { display: grid; place-items: center; width: 36px; height: 36px; border-radius: var(--radius); border: 1px solid var(--border); color: var(--brand); flex: none; background: var(--surface-inset); }
.acct-labels { display: flex; flex-direction: column; min-width: 0; }
.acct-item-title { font-weight: 600; font-size: 14px; }
.acct-item-sub { font-size: 12px; color: var(--ink-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Role tag under the identity head (Client / Espace notaire). Outline pill, brand
   ink — never a filled swatch — so it reads as a label in both themes. */
.acct-role { align-self: flex-start; margin-top: 4px; font-size: 10px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--brand); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 1px 8px; }
/* Role-aware action rows reuse .acct-item; the group is just a stack. */
.acct-actions { display: flex; flex-direction: column; padding: 0 2px; }
/* Section label inside the account panel — small uppercase header that groups
   the rows below it (Compte, Notifications, Personnalisation). */
.acct-section-label {
  font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .08em; color: var(--ink-muted); padding: 6px 10px 4px;
}
/* Unread notary messages (ADR 0033) ride the « Mon profil » door: a filled
   square count, brand on brand-ink. */
.acct-badge {
  display: inline-flex; align-items: center; justify-content: center; margin-left: auto;
  min-width: 20px; height: 20px; padding: 0 6px; font-size: 11px; font-weight: 800;
  border-radius: var(--radius-sm); background: var(--brand); color: var(--brand-ink);
  font-variant-numeric: tabular-nums;
}
.acct-sep { height: 1px; background: var(--border); margin: 8px 4px; }
.acct-panel .notif-head { padding: 4px 10px 2px; border-bottom: 0; }
.acct-panel .notif-head-title { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; }
.acct-panel .notif-list { max-height: min(320px, 50vh); }
/* Legal links cluster at the foot of the account menu — compact wrapping links,
   not full-width buttons, so it reads as a footer. */
.acct-legal { display: flex; flex-wrap: wrap; gap: 2px; padding: 2px 2px 4px; }
.acct-legal-link { appearance: none; border: 0; background: transparent; color: var(--ink-muted); font: inherit; font-size: 12px; font-weight: 600; padding: 6px 8px; border-radius: var(--radius-sm); cursor: pointer; }
.acct-legal-link:hover { background: var(--action-tint); color: var(--ink); }
.acct-legal-link:focus-visible { background: var(--action-tint); outline: 2px solid var(--ring); outline-offset: -2px; }
/* Logged-out auth buttons (login + signup); the avatar takes over once signed in
   — the whole account wrap (bell + panel) is [hidden] while anonymous. */
.header-auth { display: inline-flex; align-items: center; gap: 6px; flex: none; }
.header-auth[hidden] { display: none; }
.header-auth .btn { white-space: nowrap; }
/* Safety cap so a long notifications list can never push the menu past the
   viewport. The cap subtracts the sticky header the panel hangs from (plus its
   8px gap and an 8px floor margin) — a bare 88vh ignored that offset and let
   the panel's bottom edge run past short landscape viewports. dvh line for
   mobile URL-bar honesty; the vh line above it is the older-browser fallback. */
.acct-panel { max-height: min(calc(100vh - var(--header-h) - 16px), 660px); overflow-y: auto; overscroll-behavior: contain; }
.acct-panel { max-height: min(calc(100dvh - var(--header-h) - 16px), 660px); }

/* Color customization section — the native <input type="color"> is wrapped in
   a styled swatch so the picker reads as part of the design system, not a
   browser artifact. The swatch is a 36px circle with the live colour as its
   background; the hidden input sits on top with opacity:0 so clicks reach it. */
.acct-colors { padding: 8px 2px 4px; }
.acct-colors-title {
  display: block; font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .1em; color: var(--ink-muted); padding: 12px 12px 8px;
}
.acct-color-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; padding: 0 12px 8px; }
.acct-color-field {
  display: flex; align-items: center; gap: 10px;
  font-size: 13px; color: var(--ink); cursor: pointer;
}
.acct-color-field input[type='color'] {
  appearance: none; border: 2px solid var(--border); border-radius: 50%;
  width: 36px; height: 36px; padding: 0; cursor: pointer; background: none;
  transition: border-color var(--motion-fast), transform var(--motion-fast), box-shadow var(--motion-fast);
}
.acct-color-field input[type='color']::-webkit-color-swatch-wrapper { padding: 0; }
.acct-color-field input[type='color']::-webkit-color-swatch { border: 0; border-radius: 50%; }
.acct-color-field input[type='color']::-moz-color-swatch { border: 0; border-radius: 50%; }
.acct-color-field input[type='color']:hover { border-color: var(--border-strong); transform: scale(1.1); box-shadow: 0 2px 8px rgba(0,0,0,0.15); }
.acct-color-field input[type='color']:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
.acct-color-reset {
  appearance: none; border: 2px solid var(--border); border-radius: var(--radius);
  background: transparent; color: var(--ink-muted); font: inherit; font-size: 12px;
  font-weight: 600; padding: 8px 14px; margin: 4px 12px 8px; cursor: pointer;
  transition: background var(--motion-fast), color var(--motion-fast), border-color var(--motion-fast), transform var(--motion-fast);
}
.acct-color-reset:hover { background: var(--action-tint); color: var(--ink); border-color: var(--border-strong); transform: translateY(-1px); }
.acct-color-reset:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; }
.acct-color-reset:active { transform: translateY(0); }

/* --- Mobile navigation drawer (hamburger) -------------------------------- */
/* Phones and portrait tablets: the burger and its right-side drawer replace the
   inline tabs, login button and theme toggle below 900px. The wider touch
   band keeps the sticky header inside the viewport at tablet widths. */
.nav-burger {
  display: none; border: 0;
  position: relative;
}
.nav-burger svg { display: block; }
/* Three-line morph: each bar translates to the vertical centre then rotates
   to form the ✕ diagonals.  transform-origin at the viewBox midpoint so both
   diagonals cross at (12, 12). */
.nav-burger .burger-line {
  transition: transform var(--burger-dur) var(--ease-ui), opacity var(--motion-fast) var(--ease-ui);
  transform-origin: 12px 12px;
}
.nav-burger.is-open .burger-top { transform: rotate(45deg) translateY(5px); }
.nav-burger.is-open .burger-mid { opacity: 0; }
.nav-burger.is-open .burger-bot { transform: rotate(-45deg) translateY(-5px); }
.nav-burger:hover .burger-line { stroke: var(--header-ink); }
.mnav-scrim {
  position: fixed; inset: 0; z-index: 65; background: var(--backdrop);
  -webkit-backdrop-filter: blur(12px) saturate(.8); backdrop-filter: blur(12px) saturate(.8);
  opacity: 0; pointer-events: none; transition: opacity var(--motion-fast) var(--ease-ui);
}
.mnav-scrim.is-open { opacity: 1; pointer-events: auto; }
.mnav {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 70;
  width: min(320px, 84vw);
  display: flex; flex-direction: column;
  padding: var(--space-5) var(--space-7) calc(var(--space-8) + env(safe-area-inset-bottom, 0px));
  background: var(--surface); border-left: 1px solid var(--border); box-shadow: var(--shadow-lg);
  overflow-y: auto; overscroll-behavior: contain;
  /* visibility swaps AFTER the slide-out so the exit still animates; on open
     the delay is removed so the panel is interactive immediately. */
  transform: translateX(105%); visibility: hidden;
  transition: transform var(--motion-ui) var(--ease-ui), visibility 0s var(--motion-ui);
}
.mnav.is-open { transform: none; visibility: visible; transition: transform var(--motion-ui) var(--ease-ui); }
/* No page scroll behind the open drawer. */
html.nav-open, html.nav-open body { overflow: hidden; }
/* Sticky for the same reason as the dialogs' ✕: the drawer scrolls, its close
   button must not. Background so links slide under it, not through it. */
.mnav-head { --lockup-tile: 26px; position: sticky; top: 0; z-index: 2; background: var(--surface); display: flex; align-items: center; gap: 10px; padding: var(--space-2) var(--space-2) var(--space-4); }
.mnav-title { font-weight: 800; font-size: 15px; letter-spacing: -0.01em; }
.mnav-group { display: flex; flex-direction: column; }
.mnav-link {
  min-height: 44px;
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  appearance: none; background: transparent; border: 0; border-radius: var(--radius);
  padding: var(--space-5) var(--space-6); font: inherit; font-size: 14.5px; font-weight: 600;
  color: var(--ink); cursor: pointer; transition: background var(--motion-fast), color var(--motion-fast);
}
.mnav-link:is(:hover, :focus-visible) { background: var(--action-tint); text-decoration: none; color: var(--ink); }
.mnav-link.is-on { background: var(--action-tint); color: var(--action-ink); }
.mnav-link svg { flex: none; color: var(--ink-muted); }
.mnav-link.is-on svg { color: var(--action-ink); }
.mnav-link .nav-tab-badge { margin-left: auto; }
/* Focus ring drawn INSIDE the row: the drawer's rows are full-bleed, so the
   default outer ring painted a giant box around the first row on open. */
.mnav-link:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; }
/* The legal fold — the drawer's one expandable row: icon + label left,
   chevron right. Only the CHEVRON rotates on expand — the row icon sits still.
   The section links themselves are flat (ADR 0010 §2), no accordions. */
.mnav-expandrow { justify-content: space-between; }
.mnav-row-l { display: flex; align-items: center; gap: 10px; }
.mnav-row-l svg { flex: none; color: var(--ink-muted); }
.mnav-chevron { transition: transform var(--motion-fast); }
.mnav-expandrow[aria-expanded='true'] .mnav-chevron { transform: rotate(180deg); }
/* Sub-rows hang off a thin rail so they read as children of their row. */
.mnav-sub {
  display: flex; flex-direction: column; padding: 0 0 var(--space-3);
  margin-left: var(--space-6); border-left: 1px solid var(--border);
}
.mnav-sub[hidden] { display: none; }
.mnav-subitem {
  display: flex; flex-direction: column; gap: 2px; width: 100%; text-align: left;
  appearance: none; background: transparent; border: 0; border-radius: 0 var(--radius) var(--radius) 0;
  padding: var(--space-4) var(--space-6) var(--space-4) var(--space-5);
  font: inherit; color: var(--ink); cursor: pointer;
}
.mnav-subitem:hover { background: var(--action-tint); text-decoration: none; color: var(--ink); }
.mnav-subitem:focus-visible { background: var(--action-tint); outline: 2px solid var(--ring); outline-offset: -2px; }
.mnav-sep { height: 1px; background: var(--border); margin: var(--space-5) var(--space-2); flex: none; }
.mnav-auth { gap: var(--space-4); padding: 0 var(--space-2); }
.mnav-auth .btn { width: 100%; }
/* When the auth pair hides (signed in), its trailing separator must go with it
   or two hairlines stack. */
#mnav-auth[hidden] + .mnav-auth-sep { display: none; }
.mnav-legal .mnav-subitem { font-size: 13.5px; font-weight: 500; color: var(--ink-muted); padding-block: var(--space-4); }
.mnav-legal .mnav-subitem:hover { color: var(--ink); }
/* Preference rows (language, theme): label left, small toggle right. NOT
   .mnav-link — the drawer's "any choice closes" delegate must ignore them,
   because flipping a preference is not navigation. The label column reuses
   .mnav-row-l so its icon+text align with the rows above. */
.mnav-pref {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: var(--space-4) var(--space-6);
  font-size: 14.5px; font-weight: 600; color: var(--ink);
}
.mnav-pref .mnav-row-l svg { color: var(--ink-muted); }

/* Staggered entrance — each direct child of the drawer arrives --menu-stagger
   after the previous, so the panel fills top-to-bottom instead of appearing
   as a block.  --i is set inline on each element in the HTML. */
.mnav.is-open > *:not(.mnav-head) {
  animation: menuItemIn var(--menu-item-dur) var(--ease-ui) both;
  animation-delay: calc(var(--i, 0) * var(--menu-stagger));
}
/* Section labels: small uppercase headers that group the drawer rows. */
.mnav-section-label {
  font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .1em; color: var(--ink-muted);
  padding: var(--space-4) var(--space-6) var(--space-2);
  opacity: 0.7;
}

/* --- Sign-in / sign-up modal -------------------------------------------- */
.auth-modal { border: 1px solid color-mix(in srgb, var(--border-strong) 70%, var(--border)); border-radius: var(--radius-lg); background: linear-gradient(165deg, color-mix(in srgb, var(--brand) 5%, var(--surface-hover)) 0%, transparent 40%), var(--surface); color: var(--ink); box-shadow: var(--shadow-lg), inset 0 1px 0 rgb(255 255 255 / .03); padding: 0; width: min(420px, 92vw); max-height: 92vh; overflow: auto; }
/* Close ✕: the shared .dlg-x construction — see the base dialog rules. */
.auth-body { padding: 30px 26px 24px; display: flex; flex-direction: column; }
.auth-mark { display: grid; place-items: center; margin-bottom: 12px; }
.auth-mark .brand-badge {
  width: 46px; height: 46px; border-radius: var(--radius-lg); display: grid; place-items: center;
  background: var(--surface-inset); border: 1px solid var(--border);
  animation: authMarkIn var(--motion-enter) var(--ease-ui) both;
}
@keyframes authMarkIn { from { opacity: 0; transform: scale(.85); } to { opacity: 1; transform: none; } }
.auth-title { text-align: center; margin: 0; } /* a dialog title sits on the h2 rung (ADR 0050) */
.auth-sub { font-size: 13.5px; color: var(--ink-muted); text-align: center; margin: 6px 0 18px; line-height: 1.5; }
/* The base .seg lets the unselected option sit as bare text in the track, which
   reads as a label, not a button. Here both halves must read as the same kind of
   thing: equal widths, a hover fill that invites the click, and the selected one
   raised on a filled pill so the pair reads as one two-position control.
   Scoped to .auth-role only — the calendar's segments keep the base look. */
.auth-role { display: flex; width: 100%; margin-bottom: 16px; }
.auth-role .seg-btn { flex: 1; text-align: center; padding: 8px 14px; font-weight: 600; }
.auth-role .seg-btn:not(.is-on):hover { background: var(--action-tint); color: var(--ink); }
/* Not var(--surface): in dark it sits below the inset track and would read
   sunken. --surface-hover stays lighter than the track in both themes; the
   strong hairline and the bigger shadow are what separate it from a hover. */
.auth-role .seg-btn.is-on { background: var(--action-tint); border-color: var(--border-strong); box-shadow: var(--shadow); }
.auth-email { display: flex; flex-direction: column; gap: 8px; }
.auth-email .lbl { font-size: 12px; margin-bottom: 0; }
.auth-email input { width: 100%; }
.auth-continue { width: 100%; margin-top: 4px; }
.auth-fine { font-size: 12px; color: var(--ink-muted); line-height: 1.5; margin: 14px 0 0; text-align: center; }

/* --- Bascule inscription ↔ connexion ------------------------------------- */
/* Une phrase, pas un bouton : le geste principal reste le CTA au-dessus. */
.auth-switch { font-size: 13px; color: var(--ink-muted); text-align: center; margin: 14px 0 0; }
.auth-switch-btn {
  appearance: none; border: 0; background: none; padding: 0; margin-left: 4px;
  font: inherit; font-weight: 650; color: var(--action-ink); cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}
.auth-switch-btn:hover { color: var(--action-ink); }

/* --- Séparateur ---------------------------------------------------------- */
/* Le filet passe DERRIÈRE le mot, qui porte le fond de la carte : pas de
   largeur codée en dur, donc il tient dans les deux langues. */
.auth-or {
  display: flex; align-items: center; gap: 12px;
  margin: 18px 0 14px; color: var(--ink-muted); font-size: 12px;
}
.auth-or::before, .auth-or::after { content: ''; flex: 1; height: 1px; background: var(--border); }

/* --- Fournisseurs d’authentification ------------------------------------- */
.auth-social { display: flex; flex-direction: column; gap: 8px; }
.auth-social-h {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-muted); text-align: center; margin: 0 0 2px;
}
.auth-soc-list { display: flex; flex-direction: column; gap: 8px; }
/* Elles se lisent comme des boutons — c'est ce qu'elles seront — mais en
   retrait : elles n'entrent pas en concurrence avec le seul chemin qui marche.
   Pas de `filter: grayscale` : la marque doit rester reconnaissable, c'est tout
   l'intérêt de les montrer d'avance. */
.auth-soc-btn {
  appearance: none; font: inherit; cursor: not-allowed;
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 12px; border-radius: var(--radius);
  border: 1px solid var(--border); background: var(--surface);
  color: var(--ink-muted); text-align: left;
  transition: border-color var(--motion-fast), background var(--motion-fast);
}
.auth-soc-btn:hover { border-color: var(--border-strong); background: var(--action-tint); }
.auth-soc-btn:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
/* Le « G » de Google doit apparaître sur fond blanc, quel que soit le thème
   (exigence de marque) : la pastille le porte. Les deux autres logos sont
   monochromes et tiennent sur n'importe quel fond. */
.auth-soc-ic {
  display: grid; place-items: center; flex: none;
  width: 26px; height: 26px; border-radius: var(--radius-sm);
}
.auth-soc-btn[data-provider='google'] .auth-soc-ic {
  background: var(--marque-google-chip); border: 1px solid var(--border);
}
.auth-soc-t { flex: 1; font-size: 13.5px; font-weight: 600; color: var(--ink); }
.auth-social-note { text-align: center; margin: 4px 0 0; }
@media (max-width: 420px) {
  .auth-soc-btn { padding: 8px 10px; gap: 8px; }
  .auth-soc-t { font-size: 13px; }
}
/* La réponse au clic : vide, elle ne prend aucune place ; remplie, elle se lit
   comme une réponse et non comme une erreur. */
.auth-soc-live:empty { display: none; }
.auth-soc-live {
  margin: 8px 0 0; padding: 8px 10px; font-size: 12.5px; line-height: 1.45;
  color: var(--ink); text-align: center;
  background: var(--brand-tint-solid); border: 1px solid var(--border);
  border-radius: var(--radius);
}

/* --- First-visit onboarding guide --------------------------------------- */
/* Reuses the .auth-modal shell (card + backdrop); two views live in the DOM
   and are shown/hidden. Tokens only, so it tracks every theme automatically. */
/* 560px: wide enough for the week vignette's five columns to carry an act's
   name and the exact amount — "Refinancement" ellipsizes, still named by its
   glyph, colour and tooltip. The ≤380px container fallback covers phones,
   where 94vw wins. max-width included: the base `dialog` rule caps every
   dialog at 440px and would clamp it back. */
.onb-modal {
  border: 1px solid color-mix(in srgb, var(--brand-bright) 50%, var(--border-strong));
  border-radius: var(--radius-lg);
  background:
    linear-gradient(155deg, color-mix(in srgb, var(--brand) 12%, var(--surface-hover)) 0%, transparent 50%),
    color-mix(in srgb, var(--surface) 92%, var(--bg));
  color: var(--ink);
  box-shadow: 0 40px 100px rgb(0 0 0 / .6), 0 0 0 1px rgb(var(--nota-blue-500-rgb) / .25), inset 0 1px 0 rgb(255 255 255 / .05);
  padding: 0; width: min(560px, 94vw); max-width: 560px; max-height: 92vh; overflow: auto;
}
/* No scoped ::backdrop here — the shared dialog::backdrop owns the scrim, so
   every modal darkens the page the same way. The rule this replaces carried a
   hardcoded rgb(5 14 23 / .68) and its own 3px blur. */
.onb-body { padding: var(--pad-dialog); display: flex; flex-direction: column; }
.onb-title { text-align: center; margin: 0; color: var(--ink); text-shadow: 0 1px 2px rgb(0 0 0 / .1); } /* a dialog title sits on the h2 rung (ADR 0050) */
.onb-sub { font-size: var(--type-lead); line-height: var(--type-lead-lh); color: var(--ink-muted); text-align: center; margin: 6px 0 18px; opacity: 0.9; }

/* VIEW 1 — two outline choice cards, side by side, stacking on narrow screens. */
.onb-choices { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.onb-choice { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; text-align: left; padding: 16px 15px; border: 1px solid color-mix(in srgb, var(--border-strong) 60%, var(--border)); border-radius: var(--radius); background: var(--surface-inset); color: var(--ink); cursor: pointer; transition: border-color var(--motion-fast), background var(--motion-fast), transform var(--motion-fast), box-shadow var(--motion-fast); box-shadow: 0 1px 3px rgb(0 0 0 / .1); }
.onb-choice:hover, .onb-choice:focus-visible { border-color: var(--action-accent); background: color-mix(in srgb, var(--surface-hover) 60%, var(--surface-inset)); box-shadow: 0 3px 12px color-mix(in srgb, var(--action-accent) 15%, transparent); }
.onb-choice:active { transform: translateY(1px); }
.onb-choice-ic { display: grid; place-items: center; width: 40px; height: 40px; border-radius: var(--radius); background: var(--surface); border: 1px solid color-mix(in srgb, var(--border-strong) 60%, var(--border)); color: var(--brand-bright); box-shadow: 0 1px 3px rgb(0 0 0 / .1); }
.onb-choice-t { font-size: 14.5px; font-weight: 700; letter-spacing: -0.01em; }
.onb-choice-d { font-size: 12.5px; color: var(--ink-muted); line-height: 1.45; }
.onb-choice-live { min-height: 1.5em; font-size: 12px; font-weight: 650; color: var(--brand-bright); margin-top: 2px; }

/* VIEW 2 — a numbered steps list with a brand-outline number chip. */
.onb-steps-title { margin-top: 2px; }
.onb-steps { list-style: none; margin: 4px 0 20px; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.onb-step { display: flex; align-items: flex-start; gap: 12px; }
.onb-step-n { flex: none; width: 26px; height: 26px; display: grid; place-items: center; border: 1px solid color-mix(in srgb, var(--brand-bright) 50%, var(--brand)); border-radius: var(--radius-sm); color: var(--brand-bright); font-size: 13px; font-weight: 700; background: color-mix(in srgb, var(--brand) 18%, var(--surface-inset)); box-shadow: 0 1px 3px rgb(var(--nota-blue-500-rgb) / .15); }
.onb-step-body { flex: 1; min-width: 0; }
.onb-step-t { font-size: 14px; font-weight: 700; letter-spacing: -0.01em; color: var(--ink); }
.onb-step-d { font-size: 12.5px; color: var(--ink-muted); line-height: 1.45; margin-top: 2px; }
.onb-step-ic { flex: none; display: grid; place-items: center; color: var(--ink-muted); margin-top: 2px; }
.onb-cta { width: 100%; background: linear-gradient(135deg, var(--action-ink) 0%, color-mix(in srgb, var(--action-ink) 60%, var(--brand-bright)) 100%); border-color: var(--action-ink); color: var(--action-surface); box-shadow: 0 4px 20px rgb(var(--nota-blue-500-rgb) / .28), inset 0 1px 0 rgb(255 255 255 / .08); font-weight: 650; }
.onb-cta:hover { background: linear-gradient(135deg, color-mix(in srgb, var(--action-ink) 80%, var(--action-accent)) 0%, color-mix(in srgb, var(--action-ink) 50%, var(--action-accent)) 100%); border-color: var(--action-accent); color: var(--action-surface); box-shadow: 0 6px 28px color-mix(in srgb, var(--action-accent) 38%, transparent), inset 0 1px 0 rgb(255 255 255 / .12); transform: translateY(-1px); }
/* Where-am-I marker for the two-view flow. */
.onb-progress { font-size: 11px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--brand-bright); text-align: center; margin: 0 0 16px; text-shadow: 0 0 12px rgb(var(--nota-blue-500-rgb) / .2); }
/* The low-commitment exit: real enough to see, quiet enough not to compete
   with the primary CTA above it. */
.onb-alt { width: 100%; margin-top: 10px; appearance: none; border: 1px solid color-mix(in srgb, var(--border-strong) 60%, var(--border)); border-radius: var(--radius); background: var(--surface-inset); color: var(--ink); cursor: pointer; padding: 10px 14px; font: inherit; font-size: 13.5px; font-weight: 600; transition: border-color var(--motion-fast), background var(--motion-fast), box-shadow var(--motion-fast); box-shadow: 0 1px 2px rgb(0 0 0 / .08); }
.onb-alt:hover { border-color: var(--action-accent); background: color-mix(in srgb, var(--surface-hover) 50%, var(--surface-inset)); box-shadow: 0 2px 6px rgb(0 0 0 / .12); }
.onb-back { align-self: flex-start; appearance: none; border: 0; background: transparent; color: var(--ink-muted); cursor: pointer; padding: 2px 0; margin-bottom: 8px; font: inherit; font-size: 12.5px; }
.onb-back:hover { color: var(--action-ink); }
.onb-skip { align-self: center; appearance: none; border: 0; background: transparent; color: var(--ink-muted); cursor: pointer; padding: 6px; margin-top: 12px; font: inherit; font-size: 12.5px; text-decoration: underline; }
.onb-skip:hover { color: var(--ink); }

@keyframes onb-dialog-in {
  from { opacity: 0; transform: translateY(10px) scale(.985); }
  to { opacity: 1; transform: none; }
}
@keyframes onb-view-in {
  from { opacity: 0; transform: translateY(7px); }
  to { opacity: 1; transform: none; }
}
@keyframes onb-step-in {
  from { opacity: 0; transform: translateY(5px); }
  to { opacity: 1; transform: none; }
}
.onb-modal[open] { animation: onb-dialog-in var(--motion-ui) var(--ease-ui) both; }
#onb-view-role.is-entering, #onb-view-steps.is-entering { animation: onb-view-in var(--motion-enter) var(--ease-ui) both; }
#onb-view-steps.is-entering .onb-step { animation: onb-step-in var(--motion-enter) var(--ease-ui) both; animation-delay: calc(var(--onb-step-index, 0) * 60ms); }
.onb-choice:focus-visible, .onb-alt:focus-visible, .onb-back:focus-visible, .onb-skip:focus-visible { outline: 2px solid var(--action-ink); outline-offset: 3px; }

@media (max-width: 420px) {
  .onb-choices { grid-template-columns: 1fr; }
}

/* --- Buttons ------------------------------------------------------------- */
.btn {
  appearance: none; font: inherit; font-weight: 500; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  padding: 4px 11px; border-radius: var(--radius);
  border: 1px solid var(--border); background: transparent; color: var(--ink);
  transition: background var(--motion-fast), border-color var(--motion-fast), transform var(--motion-fast);
}
.btn:not(:disabled):hover { background: var(--action-tint); }
.btn:not(:disabled):active { transform: translateY(1px); }
/* L'action principale se lit à la COULEUR DE MARQUE et à la GRAISSE, jamais à
   un aplat (propriétaire, 2026-09-12 : « je vois plusieurs boutons qui ont des
   backgrounds remplis… aucun background rempli »). La feuille le disait déjà
   pour la feuille de réservation le 2026-09-07 — « couleur de marque et graisse,
   jamais un aplat » ; la règle vaut désormais pour TOUS les boutons. L'encre
   passe par --action-ink, dérivé de l’accent du parcours et du thème. */
.btn-primary { background: transparent; color: var(--action-ink); border-color: var(--action-ink); font-weight: 700; transition: background var(--motion-fast), border-color var(--motion-fast), transform var(--motion-fast) var(--ease-ui), box-shadow var(--motion-fast) var(--ease-ui); }
/* Au survol l'action se lève et son contour se renforce — la teinte reste le
   voile opaque de --action-tint, pas une couleur pleine. */
.btn-primary:not(:disabled):is(:hover, :focus-visible) { background: var(--action-tint); border-color: var(--action-ink); color: var(--action-ink); transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.btn-primary:not(:disabled):active { transform: translateY(0); box-shadow: none; }
.btn-ghost { border-color: transparent; background: transparent; color: var(--ink-muted); }
.btn-ghost:hover { background: var(--action-tint); color: var(--ink); }
.btn-sm { padding: 3px 9px; font-size: 12.5px; }
.btn-lg { padding: 10px 20px; font-size: 14px; font-weight: 600; }

/* --- Mini icon buttons ---------------------------------------------------- */
/* The small round actions that sit ON a component (offer row, pulse row,
   notary card, footer). Icon-only by design, so every one carries a title +
   aria-label; 30px box, 44px on coarse pointers via the touch-target rule. */
.mini-btn {
  display: inline-grid; place-items: center; flex: none;
  width: 30px; height: 30px; padding: 0; font: inherit; border: 1px solid var(--border-strong); border-radius: var(--radius);
  background: none; color: var(--ink-muted); cursor: pointer;
  text-decoration: none; transition: background-color var(--motion-fast) var(--ease-ui), color var(--motion-fast) var(--ease-ui), border-color var(--motion-fast) var(--ease-ui), transform var(--motion-fast) var(--ease-ui);
}
.mini-btn:hover { background: transparent; border-color: var(--action-ink); color: var(--action-ink); text-decoration: none; }
/* Pressing compresses — the standard tactile cue for an icon-only control. */
.mini-btn:active { background: transparent; border-color: var(--action-ink); transform: scale(.94); }
.mini-btn svg { display: block; }
/* Actions stay quiet until the row they belong to is hovered or focused —
   the data reads first, the tools appear when you go for them. */
/* Disabled reads through TOKENS, never element opacity (a half-transparent
   button lets the page bleed through it): muted ink, quiet edge, flat — et
   sans aplat, sinon l'inactif serait le SEUL bouton rempli de la page. */
.btn:disabled { cursor: not-allowed; background: transparent; border-color: var(--border); color: var(--ink-muted); box-shadow: none; }
.btn svg { flex: none; }

/* A slow transition (third-party auth redirect, checkout hand-off, any submit
   awaiting a response) gets a spinner instead of a button that just sits
   there re-labelled. Keyed off the `aria-busy` attribute already set
   throughout app.js — no new markup needed anywhere it is used. Squared, not
   a ring: the brand carries no circles (registre-carre) — a chasing corner
   reads as motion just as well. `content` is forced: some buttons already
   carry their own ::after glyph (an arrow, a chevron) at higher specificity,
   and the busy state must replace that glyph, never spin it. */
button[aria-busy="true"] { cursor: wait; }
button[aria-busy="true"]::after {
  content: '' !important; flex: none; width: .9em; height: .9em;
  border: 2px solid currentColor; border-right-color: transparent; border-bottom-color: transparent;
  border-radius: var(--radius-xs);
  animation: btn-spin .6s linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }

/* Hero call-to-action — the buyer's first, obvious action */
/* Actions follow the pitch at a stable distance, independently of the aside. */
/* A touch of breathing room between the two CTAs; the margin above follows
   the spacing scale so the hero hands off at a measured distance. */
.hero-cta { display: flex; align-items: center; gap: var(--space-7); flex-wrap: wrap; margin-top: var(--space-10); padding-top: 0; }
/* Ce qui ne coûte rien, dit sous la décision et non dans les conditions
   (propriétaire, 2026-09-12). Une ligne d'aide, jamais une carte : c'est un
   fait rassurant, pas une offre. */
.hero-free { margin: var(--space-5) 0 0; max-width: 52ch; }
.hero-free strong { color: var(--ink); }
/* A slim, equal pair: ONE set height rather than padding-derived boxes, so the
   filled and the outlined button can never drift apart by a border or a wrap.
   Wide screens only — under 681px the pair keeps its full touch height. */
/* CTA buttons keep their natural padding at every width — the 44px touch
   target from .experience-paths .btn is the floor, not a ceiling. */
@media (min-width: 681px) {
  .hero-cta .btn { height: auto; }
}

/* Guided step badges (1 · 2 · 3) in the offer panel */
.step {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: var(--radius-sm); flex: none;
  background: var(--brand); color: var(--brand-ink); font-size: 11px; font-weight: 800;
}

:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }

/* --- Hero / intro -------------------------------------------------------- */
/* A touch more floor than ceiling: the hero hands off to a PANEL below, and
   the seam between an open surface and a card needs the larger share of air. */
/* No wash of its own: the intro sits under the body's edge-to-edge fade — a
   boxed glow here ends at the content column and seams against the gutter. */
.intro { padding-block: var(--intro-pad-top); }
/* Split hero: copy on the left, live content on the right — the market pulse on
   Carnet, the "how it works" steps on Notaires. Both asides are CHROMELESS (no
   card, no border, no fill): the hero is one continuous surface, and the two
   columns are tied together by a shared top edge instead of a box. */
.intro--hero { display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(0, 0.8fr); gap: clamp(16px, 2vw, 28px); align-items: stretch; }
.intro-main { min-width: 0; display: flex; flex-direction: column; justify-content: center; }
/* The pulse kicker sits on the SAME baseline as the .eyebrow opposite it:
   same 12px, same 700, same inherited 1.5 line-height (kept explicit — the
   two columns start on one line only as long as these agree). */
.hero-steps-title {
  font-size: 12px; font-weight: 700; line-height: 1.5; text-transform: uppercase;
  letter-spacing: .06em; color: var(--accent-purple); margin-bottom: 12px;
}
/* Hero pulse — live per-service medians beside the carnet hero. No rules, no
   box: the rows are separated by rhythm and by their own volume bar, and each
   one is a button that filters the carnet below. */
.pulse { container-type: inline-size; min-width: 0; display: flex; flex-direction: column; }
.pulse-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 8px 16px;
}
.pulse .hero-steps-title { margin-bottom: 0; }
.pulse-head .hero-steps-title,
.pulse-month { min-width: 0; }
/* The month never breaks (« Septembre – octobre 2026 » is one fact); the
   kicker opposite it may, and must — both were nowrap, so in a column too
   narrow for the pair they simply painted over each other. */
.pulse-month { white-space: nowrap; }
/* fr-CA dates are lower-case (`jeudi 20 août`). `text-transform: capitalize`
   title-cases every word and produced `Jeudi 20 Août`; ::first-letter gives a
   heading its opening capital without touching the month. */
.pulse-month { font-size: 12px; font-weight: 600; color: var(--ink-muted); }
.pulse-month::first-letter { text-transform: uppercase; }
/* Rows hug their content at every viewport — no stretching to match the copy
   column. Distributing them over the hero's height (space-between + flex:1)
   opened huge gaps whenever the copy column was tall or the hero stacked. */
.pulse-rows { display: grid; gap: var(--space-2); margin-top: var(--space-6); align-content: start; }
.pulse-rows .collection-empty { margin: 0; padding: 14px 12px; border: 0; color: var(--ink-muted); text-align: center; background: none; font-size: 12px; font-weight: 700; }
/* Open rows group the filter and booking action without a card surface.
   The calendar action has its own 44px target and a quiet internal divider. */
.pulse-item {
  min-width: 0; display: flex; align-items: center; gap: 8px;
  padding: 4px 5px 4px 11px;
}
.pulse-item .pulse-row { flex: 1; min-width: 0; padding: 8px 0; margin: 0; }
.pulse-item .mini-btn {
  position: relative; width: 44px; height: 44px; margin: 0;
  border-color: transparent; color: var(--ink-muted);
}
.pulse-item .mini-btn::before {
  content: ''; position: absolute; left: -4px; top: 12px; bottom: 12px;
  width: 1px; background: var(--border);
}
.pulse-item .mini-btn:hover, .pulse-item .mini-btn:focus-visible {
  color: var(--action-ink); border-color: var(--border-strong);
}
.pulse-item .mini-btn svg { width: 18px; height: 18px; }
.pulse-row {
  display: grid; grid-template-columns: auto minmax(24px, 1fr) auto; align-items: baseline;
  gap: 2px 12px; text-align: left;
  /* Bled out by its own padding so the text stays flush with the hero copy.
     The row
     STRETCHES (no width:100%, which would shrink the content box by the
     padding and pull the amounts 20px off the hero's right edge). */
  padding: 6px 10px; margin: 0 -10px;
  background: none; border: 0; border-radius: var(--radius);
  font: inherit; color: inherit; cursor: pointer;
}
/* Underline the service for hover and selection; keyboard focus keeps the
   shared focus ring. The rows remain unboxed in every state. */
.pulse-row:hover .pulse-svc, .pulse-row.is-on .pulse-svc {
  text-decoration: underline; text-underline-offset: 3px;
}
.pulse-row.is-on .pulse-svc { color: var(--action-ink); text-decoration-color: var(--action-ink); }
.pulse-svc { grid-column: 1 / 3; grid-row: 1; display: flex; align-items: center; gap: 7px; min-width: 0; font-size: clamp(12px, 1.1vw, 14px); font-weight: 700; line-height: 1.25; }
.pulse-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
/* One glyph per act, so a service is recognised before its name is read. */
.svc-ic { flex: none; display: block; }
.chip-svc { display: inline-flex; align-items: center; gap: 6px; }
.chip-svc .svc-ic { color: var(--svc-fallback, currentColor); }
.chip-svc[data-svc='refinancement'] .svc-ic { color: var(--svc-refinancement); }
.chip-svc[data-svc='financement'] .svc-ic { color: var(--svc-financement); }
.chip-svc[data-svc='testament'] .svc-ic { color: var(--svc-testament); }
.chip-svc[data-svc='procuration'] .svc-ic { color: var(--svc-procuration); }
.chip-svc.is-on .svc-ic { color: currentColor; }
.legend-item .svc-ic, .legend-status-item .svc-ic { margin-right: 1px; }
/* Two figures per act, because they answer two questions: the floor the server
   will accept at all, and what other clients are actually offering this month. */
.pulse-figs { grid-column: 3; grid-row: 1 / 3; display: flex; align-items: baseline; gap: clamp(10px, 1.4vw, 18px); min-width: max-content; white-space: nowrap; }
.pulse-fig { display: flex; flex-direction: column; align-items: flex-end; gap: 1px; }
.pulse-fig-k { font-size: 10.5px; font-weight: 600; color: var(--ink-muted); letter-spacing: .01em; white-space: nowrap; }
.pulse-fig-v { font-size: clamp(13px, 1.2vw, 15px); font-weight: 800; font-variant-numeric: tabular-nums; white-space: nowrap; }
.pulse-fig-v.is-empty { color: var(--ink-muted); font-weight: 600; }
.pulse-meta { grid-column: 1; grid-row: 2; font-size: 11.5px; color: var(--ink-muted); padding-left: 22px; white-space: nowrap; }
/* Share of the month's demand, in the service's own hue. The gauge runs the
   full middle column — from the counts to the figures — so on a wide hero the
   fill level stays readable instead of ending in a stub. */
.pulse-bar {
  grid-column: 2; grid-row: 2; align-self: center; justify-self: stretch;
  height: 4px; border-radius: var(--radius-xs);
  /* The track is --border, not --surface-inset: on dark the inset is a near
     twin of the page and the gauge read as a lone underline. The hairline
     token is tuned to stay visible against every surface in both themes, so
     the empty share of the month is a shape, not a guess. */
  background: var(--border); overflow: hidden; margin-left: 12px;
}
/* The fill eases to its level when the month's data lands — the motion is the
   "live" cue. Decelerating curve, so it settles rather than snaps. */
.pulse-bar > span { display: block; height: 100%; border-radius: inherit; min-width: 4px; transition: width var(--motion-enter) var(--ease-ui); }
.pulse-row.is-on .pulse-bar > span { background: var(--action-ink); }
/* Phones: no per-width tuning of the stacked rows here any more — below the
   hero threshold (768) the strip changes SHAPE entirely (the two side-by-side
   act cards; see the hero threshold block near the end of this file). */

/* One column below 900px: the aside stacks under the copy, still chromeless —
   separated by space alone, and with roomier rows for touch. */
@media (max-width: 900px) {
  .pulse-row { padding-block: 10px; } /* comfortable touch target when stacked */
}
.intro h1 { margin-top: 4px; }
/* The lede mirrors the beta's: same size, leading and measure. */
.intro p { color: var(--ink-muted); max-width: 47ch; margin: 16px 0 0; font-size: var(--type-lead); line-height: var(--type-lead-lh); }
/* Block, not inline-block: as an inline box it sat on the line-box strut, so on
   wide viewports (where it fits on ONE line) it dropped ~4px below the aside's
   kicker opposite it and the two hero columns started off-line. */
.eyebrow {
  display: block; font-size: var(--type-eyebrow); font-weight: var(--weight-display); line-height: 1.5; text-transform: uppercase;
  letter-spacing: var(--type-eyebrow-ls); color: var(--ink); margin-bottom: 16px;
}


/* --- Layout -------------------------------------------------------------- */
/* Only set vertical padding here — the horizontal padding comes from .wrap.
   A `padding: … 0 …` shorthand would reset .wrap's side padding, pushing the
   panels 28px past the hero content on each side (misalignment). */
/* minmax(0, 1fr), not 1fr: a bare 1fr's auto minimum is the panel's
   min-content, and the filter bar's nowrap scroll rows would force the track
   (and the page) wider than the phone viewport instead of scrolling. */
.layout { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(14px, 2vw, 20px); padding-top: clamp(4px, 0.8vw, 8px); padding-bottom: clamp(24px, 4vw, 40px); align-items: start; }
/* Full-screen calendar (Fullscreen API on #carnet-panel): fill the viewport
   with a padded surface and taller day cells that use the extra height. */
#carnet-panel:fullscreen, #carnet-panel:-webkit-full-screen {
  background: var(--surface); padding: 10px 18px 20px; overflow: auto; border-radius: 0;
}
#carnet-panel:fullscreen .cal-cell, #carnet-panel:-webkit-full-screen .cal-cell { min-height: clamp(88px, 11vh, 128px); }

.panel {
  background: var(--surface);
  /* Ringless (owner: « ensure there is no clash with the calendar ») — a 1px
     border against the tinted band read as a box again; the gradient surface
     and the shadow carry every panel now. */
  border: 0;
  border-radius: var(--radius-lg); box-shadow: var(--shadow);
}
/* The calendar wears the shared 90 % skin (owner, 2026-08-27 evening: « une
   petite touche d'opacité pour le calendrier, environ 90 % » — superseding the
   morning's fully-opaque call, which had itself retired an 80 % backing). The
   backdrop blur keeps every cell legible: the drifting dice read as soft
   light through the veil, never as marks under the grid. */
#carnet-panel { background: var(--surface-veil); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); }
.panel-pad { padding: var(--space-9); }

/* --- Filters ------------------------------------------------------------- */
.filters { display: flex; flex-wrap: wrap; gap: 8px; padding: 12px 18px; }
.field { display: flex; flex-direction: column; gap: 4px; }
.field > label { font-size: 11px; font-weight: 600; color: var(--ink-muted); text-transform: uppercase; letter-spacing: .04em; }
select, input[type='text'], input[type='email'], input[type='tel'], input[type='number'], input[type='date'], textarea {
  font: inherit; padding: 8px 10px; border: 1px solid var(--border-strong);
  border-radius: var(--radius); background: var(--surface); color: var(--ink); min-width: 120px;
}
select:focus, input:focus, textarea:focus { border-color: var(--ring); outline: none; box-shadow: 0 0 0 3px var(--focus-ring); }
textarea { display: block; width: 100%; resize: vertical; }
/* Native checks everywhere take the brand accent — the scoped rules below
   (.check-line, .crit-flag, …) are kept as documentation of intent. */
input[type='checkbox'], input[type='radio'] { accent-color: var(--brand); }

/* --- Nota select ---------------------------------------------------------- */
/* The brand-styled dropdown drawn over a native <select> (enhanceSelect in
   app.js). The OS paints the native options popup with the OS appearance, not
   the page theme — a dark Nota page could open a white system menu — so the
   popup is ours to draw. The native control stays inside the wrapper, visually
   retired but still the form's source of truth. */
.nselect { position: relative; }
.nselect-native {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
.nselect-btn {
  font: inherit; display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; min-width: 120px; padding: 8px 10px; text-align: left; cursor: pointer;
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  background: var(--surface); color: var(--ink);
  transition: border-color var(--motion-fast), box-shadow var(--motion-fast);
}
.nselect-btn:hover { border-color: var(--action-ink); }
.nselect-btn:focus-visible { border-color: var(--ring); outline: none; box-shadow: 0 0 0 3px var(--focus-ring); }
/* The chevron is two border strokes, so it reads in the ink of every theme. */
.nselect-btn::after {
  content: ''; flex: none; width: 7px; height: 7px; margin-top: -3px;
  border-right: 2px solid var(--ink-muted); border-bottom: 2px solid var(--ink-muted);
  transform: rotate(45deg); transition: transform var(--motion-fast);
}
.nselect.is-open .nselect-btn::after { transform: rotate(-135deg); margin-top: 3px; }
.nselect-value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nselect-value.is-placeholder { color: var(--ink-muted); }
.nselect-list {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 40;
  margin: 0; padding: 4px; list-style: none; max-height: min(280px, 40vh); overflow: auto;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
}
.nselect-list[hidden] { display: none; }
.nselect-opt { padding: 7px 10px; border-radius: var(--radius-sm); cursor: pointer; font-size: 13.5px; color: var(--ink); }
.nselect-opt:hover, .nselect-opt.is-active { background: var(--action-tint); }
.nselect-opt[aria-selected='true'] { color: var(--action-ink); font-weight: 600; }

/* --- Filter panel: hidden until opened from the toolbar ------------------ */
.filterbar {
  margin: 0 0 var(--space-3); padding: var(--pad-card); display: flex; flex-direction: column; gap: var(--space-5);
  background: var(--surface-inset); border: 1px solid var(--border); border-radius: var(--radius);
}
.filterbar[hidden] { display: none; }
.filterbar-row { display: flex; flex-wrap: wrap; gap: 10px 14px; align-items: center; }
.chip-group { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  appearance: none; font: inherit; font-weight: 500; font-size: 12.5px; cursor: pointer;
  padding: 5px 12px; border-radius: var(--radius); border: 1px solid var(--border);
  background: transparent; color: var(--ink-muted); white-space: nowrap;
  transition: background var(--motion-fast), color var(--motion-fast), border-color var(--motion-fast), box-shadow var(--motion-fast), transform var(--motion-fast);
}
.chip:hover { border-color: var(--action-ink); color: var(--ink); transform: translateY(-1px); }
.chip:active { transform: translateY(0); }
.chip.is-on { background: transparent; border-color: var(--action-ink); color: var(--action-ink); font-weight: 600; box-shadow: none; }
.chip.sm { font-size: 11.5px; padding: 4px 11px; }

.seg { display: inline-flex; background: var(--surface-inset); border: 1px solid var(--border); border-radius: var(--radius); padding: 3px; gap: 2px; }
.seg-btn {
  appearance: none; font: inherit; font-weight: 500; font-size: 12.5px; cursor: pointer;
  padding: 5px 12px; border-radius: var(--radius-sm); border: 1px solid transparent; background: transparent; color: var(--ink-muted);
  transition: background var(--motion-fast), color var(--motion-fast), box-shadow var(--motion-fast), border-color var(--motion-fast);
}
.seg-btn:hover { color: var(--ink); }
/* Selected chip reads RAISED off the track: a fill lighter than the inset track
   plus a strong hairline, so it never looks sunken in dark. */
.seg-btn.is-on { background: var(--action-tint); color: var(--action-ink); border-color: var(--border-strong); box-shadow: var(--shadow-sm); }

/* --- Calendar ------------------------------------------------------------ */
.cal-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; row-gap: 8px; padding: 10px 14px; }
/* 44px targets 4px apart still mis-tap: 8px is the floor between neighbours. */
.cal-nav { display: inline-flex; gap: var(--space-4); }
.cal-title { font-weight: 700; font-size: 15px; white-space: nowrap; }
.cal-title::first-letter { text-transform: uppercase; }
/* Active-filter count riding on the Filtres toggle. */
.filter-count {
  display: inline-grid; place-items: center; min-width: 17px; height: 17px; margin-left: 6px;
  padding: 0 4px; border-radius: var(--radius-sm); background: var(--brand); color: var(--brand-ink);
  font-size: 11px; font-weight: 800; line-height: 1;
}
#filters-toggle.has-active { border-color: var(--brand); color: var(--brand); }

/* The month grid is a QUERY CONTAINER: cells always keep 7 columns, so their
   content must respond to the GRID's width — not the viewport — to stay legible
   in a narrow column, in fullscreen, or on a phone. See the @container rules below. */
.cal-grid { container: cal / inline-size; display: flex; flex-direction: column; gap: 5px; padding: 6px 14px 12px; }
.cal-empty { margin: 0 14px 12px; padding: 10px 14px; text-align: center; color: var(--ink-muted); border: 1px dashed var(--border); border-radius: var(--radius); }
.cal-row { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; }
.cal-dow { text-align: center; font-size: 11px; font-weight: 700; color: var(--ink-muted); padding: 4px 0; text-transform: uppercase; letter-spacing: .04em; }
.cal-cell {
  background: transparent; min-height: clamp(68px, 5.4vw, 98px); padding: 6px 8px 12px; position: relative;
  min-width: 0;
  display: flex; flex-direction: column; gap: 3px; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius-sm); scroll-margin-top: var(--sticky-top);
  text-align: left; font: inherit; color: var(--ink);
  transition: transform var(--motion-fast) var(--ease-ui), box-shadow var(--motion-fast) var(--ease-ui), border-color var(--motion-fast);
}
/* z-index rides the lift: the transform makes the hovered cell a stacking
   context, which traps the .svc-tip bubble's own z-index — without this the
   DOM-later neighbour paints over the bubble mid-hover. */
.cal-cell:hover { background: var(--action-tint); border-color: var(--border-strong); transform: translateY(-1px); box-shadow: var(--shadow-sm); z-index: 5; }
/* Adjacent-month days: present and readable, but clearly not this month.
   The date sits at the same weight a past day does.
   A future one navigates to its own month, so it takes a pointer. */
.cal-cell.is-out { background: transparent; cursor: default; }
.cal-cell.is-out .cal-daynum { color: var(--border-strong); }
.cal-cell.is-out.is-nav { cursor: pointer; }
.cal-cell.is-out.is-nav:hover .cal-daynum { color: var(--ink-muted); }
/* Past dates: inert, but kept in the grid so no row is lost. */
.cal-cell.is-past { background: transparent; cursor: default; pointer-events: none; box-shadow: none; }
.cal-cell.is-past .cal-daynum { color: var(--border-strong); }
.cal-cell.is-selected { border-color: transparent; box-shadow: inset 0 -3px 0 var(--action-ink); background: var(--action-tint); }
.cal-cell:focus-visible { outline: none; border-color: var(--action-ink); box-shadow: 0 0 0 3px var(--focus-ring); }
/* Demand days carry NO box of their own: the price + chance% (and the thin left
   tier strip) are the signal. No fill, no border — empty days stay blank, so the
   month reads as figures on a grid, not a wall of blue rectangles. */
.cal-cell.has-bids { background: transparent; }
.cal-cell.has-bids:hover { background: var(--action-tint); }
/* Urgency, said in words and only on the dates where it changes the decision.
   A calm date shows nothing: its tier is a pure function of the date the cell
   already prints, so a marker there is noise. Elevated dates get a named label
   plus a matching left edge — colour reinforces the word, it never carries the
   meaning alone. */
/* IN FLOW at every width, between the date and the prices (it is what the
   price MEANS, so it reads before it). It was absolutely positioned top-right
   and printed over the day number on every mid-width grid (tablet, narrow
   desktop) — a badge in flow can never overlap anything, at any resolution. */
.cal-urgency {
  position: static; align-self: flex-start; order: 1;
  font-size: 11px; font-weight: 800; letter-spacing: .01em; white-space: nowrap;
  color: var(--ink-muted);
}
.cal-svc-bids, .cal-avg { order: 2; }
.cal-more { order: 3; }
.cal-urgency[data-tier='rapide'] { color: var(--tier-rapide-ink); }
.cal-urgency[data-tier='prioritaire'] { color: var(--tier-prioritaire-ink); }
.cal-urgency[data-tier='urgence'] { color: var(--tier-urgence-ink); }
/* The steepest step is the one a client must not miss: it takes the darkest
   ink of the four, but no fill — no number in the grid carries a background
   (owner, 2026-09-10), the word and the colour say it. */
.cal-urgency[data-tier='extreme'] { color: var(--tier-extreme-ink); }
.legend-mult { font-weight: 800; }
.cal-cell[data-tier]::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  pointer-events: none;
  background: var(--tier-standard);
}
.cal-cell[data-tier='rapide']::before { background: var(--tier-rapide); }
.cal-cell[data-tier='prioritaire']::before { background: var(--tier-prioritaire); }
.cal-cell[data-tier='urgence']::before { background: var(--tier-urgence); }
.cal-cell[data-tier='extreme']::before { background: var(--tier-extreme); width: 3px; }
/* align-self keeps the box on the text: a stretched flex item would span the
   whole cell and sit under the (absolute) chevron for no reason. min-height
   clears the chevron's 26px hit circle (top:4), so the in-flow price badge on
   the next line can never slide under it, however narrow the cell gets. */
.cal-daynum { font-size: 12px; font-weight: 600; color: var(--ink-muted); align-self: flex-start; min-height: 24px; }
/* The rolling window carries a month seam inside the grid: the 1st names its
   month beside the number ("1 sept"), the way every booking calendar labels it. */
.cal-daynum[data-month]::after {
  content: " " attr(data-month);
  font-size: 10px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--ink-muted);
}
/* Today is said in ink alone — brand colour and the heavy weight, no fill.
   Owner, 2026-09-10: « remove the colour fill from the 10 and any number » —
   a filled square read as a button, and a date is a fact, not a control. */
.cal-cell.is-today .cal-daynum {
  align-self: flex-start; display: inline-flex; align-items: center;
  min-height: 20px; color: var(--brand); font-weight: 800;
  /* The phone grid prints the weekday as ::before with a trailing space —
     flex layout drops that space from the flow, fusing « JEU27 ». The pill
     carries its own gap (inert on desktop, where no ::before exists). */
  gap: 4px;
}
/* Cell content: the day's AVERAGE offer (headline) + a plain availability chip. */
.cal-avg { font-size: 16px; font-weight: 800; letter-spacing: -0.02em; margin-top: auto; white-space: nowrap; color: var(--ink); }
/* Available days stay brand-tinted (inviting); fully-taken days read muted. */
.cal-cell.is-taken { background: var(--surface-inset); }
.cal-cell.is-taken:hover { background: var(--action-tint); }
/* --- Per-act prices, and the chevron that opens the detail ---------------- */
/* A dot plus a price. The dot's colour is decoded by the Service key in the
   legend, so the act's name is never repeated on a cell or a card. */
.svc-bid { display: inline-flex; align-items: baseline; gap: 5px; min-width: 0; max-width: 100%; }
.svc-bid-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; align-self: center; }
.svc-bid-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
/* In a cell the glyph carries the act, so it is tinted rather than outlined. */
.svc-bid .svc-ic { align-self: center; }
.svc-bid-amount { font-weight: 800; letter-spacing: -0.02em; white-space: nowrap; }

/* A calendar cell prints the dot and the price only. Hovering the row raises a
   bubble that names the act — icon first — and, below, what the cell has no
   room to say: how many offers are still open and the act's starting price,
   so the printed figure reads as high or low at a glance. The same words sit
   in the DOM for screen readers. The bubble inherits the row's service colour
   as currentColor, which tints its wash, edge and icon without a per-service
   rule. Nothing on the path to the grid clips, so it escapes its cell cleanly. */
.cal-svc-bids .svc-bid { position: relative; }
.svc-tip {
  position: absolute; bottom: calc(100% + 8px); left: -6px;
  z-index: 6; padding: 10px 14px; border-radius: var(--radius);
  background: color-mix(in srgb, currentColor 9%, var(--surface));
  border: 1px solid color-mix(in srgb, currentColor 45%, var(--border-strong));
  border-left: 3px solid currentColor; box-shadow: var(--shadow);
  width: max-content; max-width: 260px;
  display: none; flex-direction: column; gap: 4px; pointer-events: none;
}
.svc-tip-head { display: inline-flex; align-items: center; gap: 7px; }
.svc-tip-head .svc-ic { flex: none; }
.svc-tip-name { color: var(--ink); font-size: 13.5px; font-weight: 700; }
.svc-tip-detail { color: var(--ink-muted); font-size: 12.5px; font-weight: 600; line-height: 1.4; white-space: normal; }
/* The bubble hangs off its row's left edge; in the last two columns that runs
   past the grid's right edge, so it right-aligns there instead. */
.cal-row .cal-cell:nth-child(n+6) .svc-tip { left: auto; right: -6px; }
@media (hover: hover) and (pointer: fine) {
  .cal-svc-bids .svc-bid:hover .svc-tip { display: flex; }
}
@media (prefers-reduced-motion: reduce) {
  .svc-tip { transition: none; }
  /* Motion-flavoured polish (lifts, nudges, eased fills) goes still; colour
     and shadow state changes remain. */
  .btn-primary, .mini-btn, .pulse-item, .pulse-bar > span, .cal-cell { transition: none; }
  .btn-primary:not(:disabled):hover, .cal-cell:hover { transform: none; }
  .mini-btn:active { transform: none; }
}
.cal-svc-bids { display: flex; flex-direction: column; gap: 2px; margin-top: auto; min-width: 0; font-size: 12.5px; }
.cal-svc-bids .svc-bid { min-width: 0; }

/* Collapsed is the resting state everywhere. The chevron is the only way in, so
   it works the same with a mouse, a finger or a keyboard. */
.cell-chevron {
  position: absolute; top: 4px; right: 4px; display: grid; place-items: center;
  width: 26px; height: 26px; padding: 0; appearance: none; font: inherit; border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--ink-muted); cursor: pointer;
  transition: transform var(--motion-fast) var(--ease-ui), background var(--motion-fast) var(--ease-ui), color var(--motion-fast) var(--ease-ui);
}
.cell-chevron:hover { background: var(--action-tint); color: var(--ink); }
/* On a touch screen the 26px glyph keeps its size; its hit area grows to the
   44px the rest of the app promises on coarse pointers (the ✕ of a dialog, the
   legal nav) — the same pseudo-element trick, so nothing in the cell moves. */
@media (pointer: coarse) {
  .cell-chevron { position: relative; }
  .cell-chevron { position: absolute; }
  .cell-chevron::before { content: ''; position: absolute; inset: -9px; }
}
/* --- Touch targets: the 44px promise, kept everywhere a finger lands ---------
   The 2026-09-11 twelve-viewport audit read every interactive control on a
   coarse pointer. The ones below sat between 18 and 38px: legible, but a
   miss for a thumb. Each keeps its resting size on a mouse; on touch it grows
   its hit area — by min-height where the control is a block, by a ::before
   extension where its box must not move (a switch, a fold glyph). Inline
   links set in running text are exempt (WCAG 2.5.8), so nothing here touches
   them. */
@media (pointer: coarse) {
  .book-rail-b, #day-date, .day-bids-toggle, .offer-hint-link, .sup-chip, #chat-topic-search,
  #onb-skip, #nc-cnq, #auth-switch-btn, .password-toggle { min-height: 44px; }
  .crit-sec-fold, #chat-close, .mini-seg-btn, .tswitch { position: relative; }
  .crit-sec-fold::before, #chat-close::before { content: ''; position: absolute; inset: -10px; }
  .mini-seg-btn { min-width: 44px; }
  .mini-seg-btn::before { content: ''; position: absolute; inset: -10px 0; }
  /* ::after, PAS ::before : ::before est le galet de l'interrupteur (24 px,
     fond, cadre, ombre). Le redéclarer ici écrasait sa géométrie et le
     poussait hors de la piste sur tout pointeur grossier — c'est-à-dire sur
     tous les téléphones (capture du propriétaire, 2026-09-12). */
  .tswitch::after { content: ''; position: absolute; inset: -8px -4px; }
}
.cell-chevron[aria-expanded='true'] { transform: rotate(180deg); }
/* Touch: 26px alone is a mis-tap magnet. A transparent halo grows the hit
   circle to 40×40 without moving a pixel of layout — the glyph (and its
   expanded-state rotation, which the pseudo simply follows) stays put. */
@media (pointer: coarse) {
  .cell-chevron::after { content: ''; position: absolute; inset: -7px; border-radius: 50%; }
}

/* What the chevron reveals. */
.cal-more { display: none; }
.cal-cell.is-expanded .cal-more { display: flex; flex-wrap: wrap; gap: 2px 8px; margin-top: 4px; font-size: 10.5px; line-height: 1.35; color: var(--ink-muted); }
.cal-more-beat { font-weight: 700; color: var(--brand); }
/* An expanded cell must be able to outgrow its row without shoving neighbours. */
.cal-cell.is-expanded { z-index: 3; background: var(--surface); border-color: var(--border-strong); box-shadow: var(--shadow-lg); }




/* Responsive cells, driven by the GRID width (7 columns are fixed, so cell width
   ≈ grid width / 7). Detail is shed progressively so the essentials — day number,
   count, top price, urgency strip, service-mix + status bars — always fit cleanly
   at every resolution, and nothing ever clips mid-word. */
@container cal (max-width: 740px) {
  .cal-avg { font-size: 13px; }
  .cal-svc-bids .svc-bid-amount { font-size: 11.5px; }
  /* "En attente / Approuvé / Expiré" would clip, so collapse the own-offer badge to a status dot. */
}
@container cal (max-width: 560px) {
  .cal-cell { padding: 6px 6px 12px; min-height: clamp(66px, 15cqw, 96px); }
  .cal-daynum { font-size: 11px; }
  /* Cells get too narrow for "3 285 $": swap to the compact form (data-compact),
     which always fits. The full amount stays in the DOM + day dialog for a11y. */
  .cal-svc-bids .svc-bid-amount { font-size: 0; }
  .cal-svc-bids .svc-bid-amount::after { content: attr(data-compact); font-size: 11px; font-weight: 800; }
  .cal-avg { font-size: 0; }
  .cal-avg::after { content: attr(data-compact); font-size: 12.5px; font-weight: 800; letter-spacing: -0.02em; }
}
/* The in-flow urgency badge is ~66px at its widest ("dès 4 000 $", the 2× same-day
   ceiling on the 2 000 $ floor) and needs an
   ~84px cell — a 620px seven-column grid — or its nowrap text runs into the
   next day (measured 1-20px of bleed from 710px down to 500px viewports).
   Under that, swap it to the compact figure (data-compact, the same pattern as
   the amounts above). The full label stays in the DOM and in the badge's
   title, so screen readers and hover keep the exact price. */
@container cal (max-width: 620px) {
  .cal-urgency { font-size: 0; }
  .cal-urgency::after { content: attr(data-compact); font-size: 11px; font-weight: 800; letter-spacing: .01em; }
}
/* Phones. Seven columns are not negotiable, so on a 320px screen a cell is 34px
   wide with a 26px content box, and a glyph + gap + compact amount laid out in a
   ROW needs 45px. The row was clamped to the box while its text carried on
   painting over the next day, because the tooltip above deliberately leaves
   nothing on the path to the grid clipping. That tooltip is display:none without
   a fine pointer, so here the cell can safely contain its own content again.
   Measured at 320/375/414: every act still prints its price, and nothing leaves
   its cell. The cost is height (87px -> 127px at 320), which a phone scrolls. */
/* PHONES: the month grid drops from 7 columns to 3.
   Seven columns on a 320px screen give a 34px cell, which cannot carry a glyph
   and a price side by side however the content is tuned — the previous attempt
   stacked them and still had to compact "1 900 $" down to "1,9k". Three columns
   give an 82px cell, wider than the 7-column cell is at ANY phone size, so the
   cell renders the way it does on a desktop and the prices come back in full.

   What that costs: a cell is no longer under a weekday column, so the weekday
   header row goes and each cell prints its own ("MER 19", app.js sets data-dow).
   Empty padding cells and past days are dropped rather than blanked, so the grid
   opens on today and packs 13 real dates into 5 rows instead of 21 slots into 3.

   This is keyed on a container on the grid's PARENT: an element cannot respond
   to its own container query, and .cal-grid is the `cal` container itself. */
#view-calendrier { container: calwrap / inline-size; }
@container calwrap (max-width: 468px) {
  .cal-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-3); }
  .cal-row { display: contents; }
  .cal-dow-row { display: none; }
  /* Out-of-month blanks exist ONLY to hold a weekday column, and there are no
     weekday columns here. The dead history that anchors the rolling window's
     first week holds no place either: the phone grid opens on today. */
  .cal-cell.is-out, .cal-cell.is-past { display: none; }
}
/* Cell content in reflowed mode. The `cal` container is still narrow here, so
   the ≤560 compact-money swap is still matching — but the CELL is now 82px, and
   grid width no longer implies cell width once the column count changes. */
@container cal (max-width: 440px) {
  .cal-cell { padding: 7px 9px 10px; gap: 3px; overflow: hidden; }
  /* One stable header row: the label owns the cell's width and ellipsizes
     ("MAR 1 SE…") instead of wrapping under the chevron. The chevron corner is
     reserved only on offer days (the only cells that carry one), and never for
     today's date-circle — a padded pill would smear its fill sideways; the
     pill is short ("MER 27") and clears the glyph on its own. */
  .cal-daynum { align-self: stretch; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .cal-cell.has-bids:not(.is-today) .cal-daynum { padding-right: 30px; }
  /* The month seam used to ride the date line and ellipsized into
     « MAR 1 SE… » wherever the chevron reserve ate the right edge. A seam
     cell may wrap instead: « MAR 1 » stays whole and the month reads as its
     own quiet line beneath it — no leading space, it owns the line. */
  .cal-daynum[data-month] { white-space: normal; }
  .cal-daynum[data-month]::after { content: attr(data-month); display: block; line-height: 1.3; }
  /* Offer lines breathe the same whether the day holds one or three. */
  .cal-svc-bids { gap: 3px; }
  .cal-daynum::before {
    content: attr(data-dow) " ";
    font-size: 10px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  }
  /* An 82px cell fits "1 900 $" (57px with its glyph). Undo the compaction. */
  .cal-svc-bids .svc-bid-amount { font-size: 11.5px; }
  .cal-svc-bids .svc-bid-amount::after { content: none; }
  /* Three-column cells are ≥93px down to a ~350px screen: the full urgency
     label fits again. */
  .cal-urgency { font-size: 11px; }
  .cal-urgency::after { content: none; }
}
/* The very smallest screens (≤~350px): three-column cells drop under 83px and
   the widest label ("dès 4 000 $", ~66px) no longer fits — back to compact. */
@container cal (max-width: 265px) {
  .cal-urgency { font-size: 0; }
  .cal-urgency::after { content: attr(data-compact); font-size: 11px; font-weight: 800; letter-spacing: .01em; }
}

/* --- Agenda / bid list --------------------------------------------------- */
/* Agenda: a dense responsive grid of day-cards so it fills the full width below
   the calendar (no sparse full-width rows / blank space). */
/* Row-aligned grid: day-groups line up in tidy rows/columns. Each day shows only
   its best offer (the rest behind "+N autres offres"), so heights stay close and
   rows align without large gaps. */

/* Same bargain as the calendar cell: the resting card stays simple — the day,
   one amount, the odds — and hover is where a client digs into what it takes to
   be retained. Fine pointers only; on touch the tap opens the day dialog, which
   carries the same detail. */

/* Without hover (touch), the coaching line is simply always there. */

/* A day with no bet is still a full rectangle: the placeholder fills the card and doubles as a "reserve this date" affordance. */
/* The card header carries the date and, like the calendar cell, the odds of
   getting a notary that day — the list was the one view showing a price with no
   sense of how gettable the date is. */
.bid-row { display: flex; align-items: center; gap: 10px; padding: 9px var(--space-12) 9px 22px; border-top: 1px solid var(--border); border-left: 2px solid transparent; }
.bid-row.is-open { border-left-color: var(--status-ouverte); }
.bid-row.is-retenue { border-left-color: var(--status-retenue); }
.status-chip {
  font-size: 11px; font-weight: 700; padding: 3px 9px; border-radius: var(--radius-sm);
  background: var(--surface); color: var(--status-retenue); border: 1px solid var(--border-strong);
  max-width: 44%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: none;
}
/* A list card is only 240-390px wide at EVERY breakpoint (the grid packs 1-4
   columns), and a single flex line cannot hold amount + name + service + tier +
   actions: the client name and the service were ellipsised into "C..." /
   "Refi..." on phones AND on a 1920 desktop alike. Give the numbers one line and
   the identity its own full-width line beneath, via `order` (the markup order is
   amount, meta, tier, actions). The day dialog keeps the single-line row — it
   has 600px to work with. */
.bid-amount { font-weight: 800; font-size: 15px; min-width: 78px; }
.bid-meta { flex: 1; min-width: 0; }
.bid-who { font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bid-sub { font-size: 12px; color: var(--ink-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pill {
  font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: var(--radius-sm);
  color: var(--on-accent); white-space: nowrap;
}
.pill[data-tier='standard'] { background: var(--tier-standard); }
.pill[data-tier='rapide'] { background: var(--tier-rapide); }
.pill[data-tier='prioritaire'] { background: var(--tier-prioritaire); }
.pill[data-tier='urgence'] { background: var(--tier-urgence); }
.pill[data-tier='extreme'] { background: var(--tier-extreme); }
.pill-retenue { background: var(--surface-inset); color: var(--ink-muted); border: 1px solid var(--border-strong); }
.tag-anon { font-size: 11px; color: var(--ink-muted); border: 1px dashed var(--border-strong); border-radius: var(--radius-sm); padding: 1px 6px; margin-left: 6px; }

.legend { display: flex; flex-wrap: wrap; gap: 8px 10px; padding: 2px 14px 10px; font-size: 12px; color: var(--ink-muted); }
.legend-item, .legend-status-item { display: inline-flex; align-items: center; gap: 6px; }
.legend-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ink); }
.legend-label--sep { margin-left: 4px; padding-left: 12px; border-left: 1px solid var(--border); }
.legend-dot { width: 10px; height: 10px; border-radius: var(--radius-sm); }
/* Full-width explainer under the colour keys: names the two figures each cell
   prints. Own line so it never competes with the dotted keys. */
.legend-note { flex: 1 0 100%; margin-top: 2px; font-size: 11.5px; line-height: 1.5; color: var(--ink-muted); }
.legend-note strong { color: var(--ink); font-weight: 700; }

/* --- Offer form (now inside the day-booking dialog) --------------------- */
.form-row { margin-bottom: 14px; }
.form-row label.lbl { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 700; margin-bottom: 8px; }
.help { font-size: 12px; color: var(--ink-muted); margin-top: 4px; }

/* --- A held line --------------------------------------------------------
   The other half of ADR 0039. Some messages CANNOT go behind an « i »: a
   validation refusal, a character counter, a « ✓ enregistré », a live status
   line. They have to be read, out loud, in place. But `hidden` means
   `display: none`, so each one still took its line away with it — and the
   button the user was aiming at moved under their cursor at the exact moment
   the refusal explained why they had missed it.

   Here `hidden` stops meaning « take the line away » and starts meaning « say
   nothing on it ». An author `display` beats the UA's `[hidden]{display:none}`,
   so the box stays; `visibility` takes the content out of sight, out of the
   focus order and out of the accessibility tree — everything `hidden`
   promised, minus the jump. `.hold-line` adds the reserved height for the
   nodes that are EMPTIED when they fall silent (an error list, a counter);
   a node that keeps its text needs `.hold` alone. */
/* Voici la liste, en un seul endroit : `.hold` pour tout nouvel arrivant, et
   les lignes déjà nommées qui la rejoignent sans changer de nom. Le `display`
   est !important parce que le tapis général `.hidden, [hidden]` l'est aussi ;
   `block` suffit partout — un enfant de flex est de toute façon « blockifié »
   par le navigateur. `.hold-line` réserve la hauteur des nœuds qu'on VIDE
   quand ils se taisent (un compteur, une liste d'erreurs) ; un nœud qui garde
   son texte n'en a pas besoin. */
.hold[hidden],
.offer-hint[hidden], .day-beat[hidden],
.chat-error[hidden], .chat-count[hidden], .nc-chat-count[hidden], .nc-chat-err[hidden],
.nc-form-errors[hidden], .nc-field-err[hidden], .onb-choice-live[hidden],
.sup-count[hidden], .sup-reply-courriel[hidden], .ct-count[hidden],
.day-market-line[hidden], .cal-avail[hidden],
#chat-reply-error[hidden], #chat-reply-sent[hidden] { display: block !important; visibility: hidden; }
/* CE QUI N'EST PAS DANS CETTE LISTE, ET POURQUOI (ADR 0046). La ligne réservée
   est faite pour un message de VALIDATION : il apparaît et disparaît sous le
   doigt du visiteur, et sans elle le formulaire sauterait à chaque frappe. Une
   NOTE DE SITUATION, elle, change une fois par conversation — et si elle garde
   sa ligne, elle la garde tout le temps. « Conversation terminée » et l'avis
   d'escalade réservaient à eux deux 108 px de vide permanent au milieu d'un
   panneau de 380 px : c'était, littéralement, le trou qui faisait paraître la
   messagerie cassée. Ils se replient donc, comme les questions d'amorce. */
/* Les deux qui sont des conteneurs flex gardent leur flex : en `block` leur
   contenu se recomposerait, et une ligne tenue changerait de hauteur — soit
   exactement ce qu'on est venu empêcher. */
.day-market-line[hidden], .cal-avail[hidden] { display: flex !important; }
.hold-line { min-height: 1.5em; }

/* --- Info tip (« ⓘ ») ----------------------------------------------------
   The house pattern for a SITUATIONAL note — « this date is short notice »,
   « few notaries travel that far », « check these older answers ». Such a
   sentence used to print itself as an extra line under the question, so an
   answer that turned it on GREW its card and pushed everything below it down
   the page; answering the next question shoved it back. The sentence now
   rides a small « i » pinned to the question's own line and opens in a panel
   that floats OVER the page: the form's height never depends on what the
   notes have to say.

   The box is reserved whether or not the tip has something to say
   (visibility, never display) — so the label line does not jitter either, and
   a hidden tip is neither focusable nor read aloud.

   Three ways in, because a tooltip that only answers the mouse answers nobody
   on a phone or a keyboard: hover, keyboard focus, and a click that PINS the
   panel open until Escape, an outside click, or another tip takes over. The
   pinned panel takes the pointer, so its sentence can be selected and copied. */
.itip { position: relative; display: inline-flex; flex: none; vertical-align: -3px; margin-left: 6px; }
.itip[data-on='false'] { visibility: hidden; }
.itip-btn {
  appearance: none; border: 0; background: none; padding: 0; margin: 0;
  position: relative;
  width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius-xs); color: var(--ink-muted); cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
/* WCAG 2.2 « Target Size (Minimum) » asks for 24 × 24 CSS px. The glyph stays
   at 18 so it never lifts the label's line — the target is grown OUTWARD by an
   invisible pad, which costs the layout nothing because it is out of flow. */
.itip-btn::after { content: ''; position: absolute; inset: -3px; }
.itip[data-tone='warn'] .itip-btn { color: var(--warn); }
.itip-btn:hover, .itip[data-open='true'] .itip-btn { color: var(--ink); background: var(--action-tint); }
.itip-btn:focus-visible { outline: 2px solid var(--action-ink); outline-offset: 1px; }
/* The panel: absolutely placed, so it costs the layout nothing. Its side and
   its alignment are chosen by script the moment it opens (placeItip), so it
   never opens off the edge of a dialog or a phone. */
/* L'aide d'une question vit maintenant DANS ce panneau : elle en prend la voix
   (le gris de .help se perdrait sur la surface du panneau) et n'y garde pas la
   marge qu'elle avait en pleine page. */
.itip-pop > .help { margin: 0; font-size: inherit; color: inherit; }
.itip-pop {
  position: absolute; z-index: 60; top: calc(100% + 6px); left: 50%; transform: translateX(-50%);
  width: max-content; max-width: min(280px, calc(100vw - 16px));
  padding: 8px 10px; text-align: left;
  font-size: 12.5px; font-weight: 500; line-height: 1.5; color: var(--ink);
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
  opacity: 0; visibility: hidden; pointer-events: none;
}
.itip[data-side='top'] > .itip-pop { top: auto; bottom: calc(100% + 6px); }
/* Hover is offered only where a pointer can actually hover: on a touch screen
   a tap leaves a « stuck » hover behind, and the panel would never close. There
   the pinning tap is the way in, and it has a way out. */
/* FERMÉE, la bulle sort de la mise en page (2026-09-06). Elle est hors flux,
   mais une boîte absolue invisible compte quand même dans le scrollWidth de son
   conteneur : à 375 px, quatre bulles de 280 px ancrées sur leur « i » faisaient
   dépasser la feuille de réservation de 30 px, et #day-dialog (overflow-y:auto,
   donc overflow-x calculé à auto) se laissait tirer de côté — rien à voir, tout
   à faire glisser. C'est la SEULE exception au registre « visibility, jamais
   display » du « i » : celui-ci ne tient aucune ligne, donc il n'en bouge
   aucune. Ouverte, elle reprend sa boîte AVANT qu'itipPlace la mesure (le clic
   pose data-open, le survol et le focus posent l'état CSS, puis l'événement). */
.itip-pop { display: none; }
@media (hover: hover) {
  .itip:hover > .itip-pop { opacity: 1; visibility: visible; display: block; }
}
.itip-btn:focus-visible ~ .itip-pop,
.itip[data-open='true'] > .itip-pop { opacity: 1; visibility: visible; display: block; }
.itip[data-open='true'] > .itip-pop { pointer-events: auto; }
@media (prefers-reduced-motion: no-preference) {
  .itip-pop { transition: opacity var(--motion-fast) var(--ease-ui), visibility var(--motion-fast); }
  /* A note that has just turned on wakes its « i » once, so a signal that no
     longer takes a line of its own is still noticed. */
  @keyframes itip-wake {
    from { box-shadow: 0 0 0 4px color-mix(in srgb, currentColor 35%, transparent); }
    to { box-shadow: 0 0 0 4px transparent; }
  }
  .itip[data-fresh='true'] .itip-btn { animation: itip-wake 1.2s ease-out; }
}

/* Inside step 3, right above the amount: WHY it is pre-filled (delay tier +
   going range). Compact and muted — context, never a competing price signal. */
.tier-preview { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tier-preview .pill { font-size: 11px; }
.tier-preview .tp-text { font-size: 12px; color: var(--ink-muted); }

.slider-row { display: flex; align-items: center; gap: 12px; }
/* La marge par défaut du navigateur (2 px) décalait la piste de son rail :
   le curseur commençait 2 px à droite du montant et des bornes au-dessus. */
input[type='range'] { flex: 1; margin: 0; accent-color: var(--brand); }
/* The slider's typed twin: a client who knows their number types it. */
.amount-input-wrap { display: inline-flex; align-items: center; gap: 4px; flex: none; }
.amount-input { width: 7ch; padding: 6px 8px; font: inherit; font-weight: 700; text-align: right; font-variant-numeric: tabular-nums; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--ink); }
.amount-input:focus-visible { outline: 2px solid var(--action-ink); outline-offset: 1px; }
.amount-input-unit { font-size: 13px; font-weight: 700; color: var(--ink-muted); }
/* Where the slider starts and stops, in dollars, under its two ends. */
.slider-bounds { display: flex; justify-content: space-between; margin-top: 2px; font-size: 11.5px; color: var(--ink-muted); font-variant-numeric: tabular-nums; }
/* The reason the publish button is dead, said before it is pressed. Each
   named question is a door back to its own line — underlined, same voice. */
.offer-hint { margin: 0 0 8px; min-height: 1.5em; font-size: 12.5px; font-weight: 600; color: var(--warn); }
.offer-hint-link {
  appearance: none; border: 0; background: none; padding: 0; margin: 0;
  font: inherit; color: inherit; cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}
.offer-hint-link:hover, .offer-hint-link:focus-visible { color: var(--ink); }
/* Law 25 small print directly under the CTA: always visible, quiet. The
   negative margin tucks it against the button despite the form's flex gap. */
.consent-line { font-size: 11.5px; line-height: 1.5; }
.day-book > .consent-line { margin-top: -12px; }
.amount-big { font-size: 26px; font-weight: 800; letter-spacing: -0.02em; }

.gauge { height: 8px; border-radius: var(--radius-xs); background: var(--surface-inset); overflow: hidden; margin: 8px 0 4px; }
.gauge-fill { width: 0; height: 100%; background: linear-gradient(90deg, var(--tier-rapide), var(--tier-prioritaire), var(--tier-urgence)); }
.gauge-label { font-size: 12px; font-weight: 600; }

/* LE DEVIS (ADR 0031) — les deux lignes que le client paie, dans l'étape du
   montant. Il doit se lire comme un reçu, pas comme une alerte : aucune
   couleur d'accent, juste un filet et une ligne de total plus lourde. Le
   supplément de Nota n'est pas une mauvaise nouvelle qu'on cache, c'est un
   prix qu'on annonce — l'art. 68 du Code de déontologie interdit la publicité
   incomplète, et une ligne discrète mais toujours visible est la réponse. */
.devis { margin-top: 10px; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-inset); }
.devis-l { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-size: 13px; line-height: 1.7; }
.devis-k { color: var(--ink-muted); }
.devis-v { font-variant-numeric: tabular-nums; font-weight: 600; }
.devis-total { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--border); font-size: 14px; }
.devis-total .devis-k, .devis-total .devis-v { color: var(--ink); font-weight: 700; }
/* La revendication du modèle n'avait AUCUNE règle : elle héritait des 16 px du
   formulaire et parlait donc plus fort que le total juste au-dessus. Elle
   compte (art. 32.1 2° L.N.), mais elle se lit après le chiffre, pas avant. */
.devis-claim { margin: var(--space-5) 0 0; font-size: 12.5px; font-weight: 600; line-height: 1.5; color: var(--ink); }
.devis-note { margin: 6px 0 0; font-size: 11.5px; line-height: 1.5; color: var(--ink-muted); }

/* Discreet inline checkbox (the bid dialog's account opt-in): plain row, no
   switch chrome — the option must read as one more optional field, not a step. */
.check-line { display: flex; align-items: center; gap: 8px; font-size: 13.5px; cursor: pointer; }
.check-line input { width: 16px; height: 16px; margin: 0; flex: none; accent-color: var(--brand); }
.check-line input:disabled { cursor: not-allowed; }
.check-line:has(input:disabled) { color: var(--ink-muted); cursor: not-allowed; }

.switch-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 0; }
.switch { position: relative; width: 42px; height: 24px; flex: none; }
.switch input { opacity: 0; width: 0; height: 0; }
.switch .track { position: absolute; inset: 0; background: var(--border-strong); border-radius: var(--radius-sm); transition: background var(--motion-fast); cursor: pointer; }
.switch .track::before { content: ''; position: absolute; width: 18px; height: 18px; left: 3px; top: 3px; background: var(--on-accent); border-radius: var(--radius-xs); transition: transform var(--motion-fast); }
.switch input:checked + .track { background: var(--brand); }
.switch input:checked + .track::before { transform: translateX(18px); }
.switch input:focus-visible + .track { box-shadow: 0 0 0 3px var(--focus-ring); }

/* Délibérément PAS une ligne tenue (ADR 0039 §5) : une liste de refus répond à
   un envoi volontaire, pas à une frappe — le saut arrive une fois, à un moment
   où l'œil est déjà sur le message. La réserver mettrait ~27 px de vide
   permanent au-dessus de six boutons d'envoi, ce qui coûte plus cher que le
   saut qu'elle éviterait. Les listes qui répondent, elles, à CHAQUE frappe
   (.nc-form-errors, .nc-field-err) tiennent bien leur ligne. */
.errors { list-style: none; margin: 8px 0 0; padding: 0; }
.errors li { color: var(--danger); font-size: 13px; padding: 2px 0; }
/* « Nous joindre »: the message counter, shown only near the cap (app.js contactCount). */
.ct-count { margin: 4px 0 0; min-height: 1.5em; text-align: right; font-variant-numeric: tabular-nums; }

/* --- Partenaires (ADR 0011) ---------------------------------------------- */
/* The entry form uses the shared landing grammar. Once a code is claimed,
   sharing and private results become a full-width workspace, rather than
   forcing the introduction to sit beside a long, narrow column.
   REFONTE DU 2026-09-20 (propriétaire : « tout l'espace est utilisé, aucun
   composant trop gros, des animations à nous, toutes les transitions douces ») :
   - sous l'introduction, les quatre étapes tiennent UNE rangée dès 1280 px
     (deux rangées entre 900 et 1280, une colonne au téléphone) ;
   - sous le héros, `.partner-gains` reprend ses deux colonnes : les gains à
     gauche, la garantie à droite, sur une seule bande ;
   - le mouvement de la porte vit en fin de bloc, sous « no-preference ». */
@media (min-width: 900.01px) {
  .partner-landing:not(:has(.pr-claim[data-state='claimed'])) { grid-template-rows: min-content 1fr; }
  .partner-landing:not(:has(.pr-claim[data-state='claimed'])) > .pr-claim { grid-column: 2; grid-row: 1 / span 2; }
  .partner-landing:not(:has(.pr-claim[data-state='claimed'])) > .pr-steps { grid-column: 1; grid-row: 2; }
  /* Devant le formulaire, les étapes s'étirent jusqu'à son bas : les deux
     colonnes du héros finissent sur la même ligne, sans bande vide à gauche.
     Pas devant le reçu « en attente » (le panneau s'allonge de 200 px : des
     tuiles de 450 px seraient le composant trop gros qu'on vient de retirer). */
  .partner-landing:has(.pr-claim[data-state='form']) > .pr-steps { align-self: stretch; }
}
/* L'introduction occupe sa colonne : la phrase tient deux lignes au lieu de
   trois, la ligne d'aide et son « Pourquoi ? » une seule. */
.partner-landing > .landing-copy > .landing-lede { max-width: 62ch; }
.partner-landing > .landing-copy > .hero-free { max-width: none; }
.partner-landing:has(.pr-claim[data-state='claimed']) { grid-template-columns: minmax(0, 1fr); }
.partner-landing:has(.pr-claim[data-state='claimed']) > .landing-copy {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-8) var(--space-16); align-items: start;
}
.partner-landing:has(.pr-claim[data-state='claimed']) > .landing-copy > :is(.eyebrow, h1, .hero-free) { grid-column: 1 / -1; }
.partner-landing:has(.pr-claim[data-state='claimed']) > .landing-copy > h1 { max-width: none; margin: 0; }
.partner-landing:has(.pr-claim[data-state='claimed']) > .landing-copy > :is(.landing-lede, .hero-cta, .hero-free) { margin: 0; }
.partner-workspace:not([hidden]) { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: var(--space-12) var(--space-16); align-items: start; }
.partner-sharing, .partner-workspace .partner-results { min-width: 0; }
.partner-workspace .partner-results { margin: 0; padding: 0 0 0 var(--space-16); border-top: 0; border-left: 1px solid var(--border); }
.pr-claim .partner-workspace > .partner-rappel-line { grid-column: 1 / -1; margin: 0; }
@media (max-width: 899.98px) {
  .partner-landing:has(.pr-claim[data-state='claimed']) > .landing-copy { grid-template-columns: minmax(0, 1fr); }
  .partner-workspace:not([hidden]) { grid-template-columns: minmax(0, 1fr); gap: var(--space-12); }
  .partner-workspace .partner-results { padding: var(--space-12) 0 0; border-left: 0; border-top: 1px solid var(--border); }
}
/* Le panneau de droite : un .panel dans le registre des grands panneaux (le
   voile ET son flou — la paire de #carnet-panel). */
.pr-claim {
  min-width: 0; padding: var(--space-9); scroll-margin-top: var(--sticky-top);
  background: var(--surface-veil);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
}
/* `.intro p` parle au texte du héros (16 px, 47ch, 16 px d'air). Le panneau est
   un formulaire posé DANS le héros : ses paragraphes reprennent la petite voix
   de .help et la largeur du panneau — sans quoi chaque aide se lisait comme
   une seconde phrase d'accroche. */
.pr-claim p { max-width: none; margin: var(--space-2) 0 0; font-size: 12px; line-height: 1.5; }
/* Survol et focus lisses sur tout ce qui se manipule dans le panneau : le champ
   prend l'encre de l'action au survol, son anneau de focus arrive en fondu ; la
   puce de métier prend la teinte de survol du registre (jamais un aplat). */
.pr-claim input { width: 100%; transition: border-color var(--motion-fast) var(--ease-ui), box-shadow var(--motion-fast) var(--ease-ui); }
.pr-claim input:hover:not(:focus) { border-color: var(--action-ink); }
.pr-claim .chip:is(:hover, :focus-visible) { background: var(--action-tint); }
/* Dès que le panneau les contient, les métiers tiennent UNE rangée (autant de
   colonnes que le domaine fournit de métiers) : entre 1100 et 1500 px la
   troisième puce passait seule à la ligne et allongeait tout le panneau. Chaque
   colonne prend la largeur de son libellé tant qu'il y a la place ; sinon le
   libellé le plus long se replie DANS sa puce, jamais sous son plus long mot.
   Plus étroit, et au téléphone, elles s'enchaînent comme partout. */
@media (min-width: 1100px) {
  .pr-claim[data-state='form'] .chip-group, .pr-claim[data-state='pending'] .chip-group { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(min-content, auto); }
  .pr-claim .chip { white-space: normal; line-height: 1.25; }
}
/* Sous le doigt, 44 px : les champs, les boutons et les puces du panneau
   grandissent par min-height ; le « Pourquoi ? », posé dans une phrase, par un
   halo qui ne bouge pas la ligne. */
@media (max-width: 600px), (pointer: coarse) {
  .pr-claim input, .pr-claim .btn, .pr-claim .chip { min-height: 44px; }
  .pr-why { position: relative; }
  .pr-why::before { content: ''; position: absolute; inset: calc(var(--space-5) * -1) 0; }
}
.pr-claim .form-row { margin-bottom: var(--space-7); }
.pr-claim span.lbl { display: block; font-size: 14px; font-weight: 700; margin-bottom: var(--space-4); }
/* « Pourquoi ? » suit la phrase qu'il explique, sur sa ligne. */
.pr-why { margin-left: var(--space-2); vertical-align: baseline; }
/* Steps sit below the introduction beside the entry form, then follow the
   full-width claimed workspace. On phones, DOM order keeps the form first.
   Dès 1280 px : UNE rangée de quatre tuiles — le chiffre et son filet en haut,
   le libellé et son détail ancrés en bas : quand la rangée s'étire jusqu'au bas
   du formulaire, l'air se loge entre les deux, jamais sous le texte. */
.pr-steps {
  list-style: none; margin: 0; padding: 0; display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-5);
}
/* L'éclat des montants (amtGlow) : sa durée vit dans un jeton local, posé sur
   les deux blocs qui portent un montant. */
.pr-steps, .partner-gains { --pr-glow-beat: 1.2s; }
/* Une étape est une carte d'accent : son trait de 3 px est celui du registre
   partagé (.accent-line), qui le TRACE à l'arrivée — de 1 à 4, c'est le fil de
   progression de la porte. Une étape n'est pas un contrôle : ni survol, ni
   curseur, ni marqueur généré sur la carte. */
.pr-card {
  --accent-line: var(--brand);
  display: flex; flex-direction: column; gap: var(--space-2);
  min-width: 0; padding: var(--space-8) var(--space-8) var(--space-7);
  border: 0; border-top: 3px solid var(--brand); border-radius: var(--radius-lg);
  background: var(--surface-veil);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  box-shadow: var(--shadow-sm);
}
/* Le quatrième pas (référer un notaire) : même grille, trait chaud — une
   récompense unique, pas un revenu récurrent. */
.pr-card--once { --accent-line: var(--accent-warm); }
/* L'ordre d'entrée : trois crans de --menu-stagger entre deux étapes, posés ici
   (la porte ne porte aucun attribut style). */
.pr-card:nth-child(2) { --reveal-i: 3; }
.pr-card:nth-child(3) { --reveal-i: 6; }
.pr-card:nth-child(4) { --reveal-i: 9; }
/* Le rang est un chiffre d'affichage, à l'encre — jamais une pastille. Dans la
   rangée de quatre, un filet de 2 px part du chiffre et file vers l'étape
   suivante ; la dernière n'en a pas : le parcours s'arrête là. */
.pr-step-num { display: flex; align-items: center; gap: var(--space-6); transform-origin: left bottom; font-family: var(--font-display); font-size: var(--type-h1); line-height: var(--type-h1-lh); letter-spacing: var(--type-h1-ls); font-weight: var(--weight-display); font-variant-numeric: tabular-nums; color: var(--ink); }
.pr-step-num::after { content: ''; flex: 1; height: 2px; background: var(--border-strong); transform-origin: left center; }
.pr-card:last-child > .pr-step-num::after { content: none; }
/* Le glyphe de l'étape (2026-09-20) : un dessin au trait qui occupe le milieu de
   la tuile quand la rangée s'étire jusqu'au bas du formulaire — l'air a une
   raison d'être. Il se DESSINE à l'arrivée (.stroke-draw, registre partagé), au
   rang de sa carte. Décor : aria-hidden, et il se retire dès que la carte
   redevient une ligne (sous 1280 px). */
.pr-step-glyph { flex: 1; display: flex; align-items: center; min-height: calc(var(--space-16) + var(--space-8)); color: var(--brand-on-surface); }
.pr-step-glyph > svg { width: calc(var(--space-16) + var(--space-12)); height: calc(var(--space-16) + var(--space-12)); }
.pr-card--once > .pr-step-glyph { color: var(--accent-warm); }
.pr-step-label { margin-top: auto; padding-top: var(--space-6); font-family: var(--font-display); font-size: var(--type-h4); line-height: var(--type-h4-lh); letter-spacing: var(--type-h4-ls); font-weight: var(--weight-display); color: var(--ink); }
.pr-step-detail { font-size: 13px; line-height: 1.5; color: var(--ink-muted); }
/* Le montant est la seule chose en bleu : un chiffre, pas un titre. */
.pr-step-detail strong { color: var(--brand-on-surface); font-variant-numeric: tabular-nums; }

/* LA BANDE DES GAINS — le second rail reprend les deux colonnes du héros : les
   deux gains sous l'introduction, la garantie sous le formulaire. Un gain est
   une LIGNE (le montant à gauche, le chemin et sa fréquence à droite), pas une
   pile de trois rangées dans une carte de 680 px. Sans survol : rien ici n'est
   interactif. */
.partner-gains { align-items: stretch; }
@media (min-width: 900.01px) {
  .partner-gains { grid-template-columns: minmax(0, 1.3fr) minmax(0, 0.8fr); column-gap: clamp(16px, 2vw, 28px); }
}
.partner-gains > .nota-guarantee { display: flex; flex-direction: column; justify-content: center; margin: 0; }
.pr-earnings { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-5); min-width: 0; }
.pr-earning-card {
  --accent-line: var(--brand);
  display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center;
  column-gap: var(--space-8); min-width: 0; padding: var(--space-7) var(--space-8) var(--space-6);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}
.pr-earning-card--once { --accent-line: var(--accent-warm); }
.pr-earning-card:nth-child(2) { --reveal-i: 3; }
/* Le chemin est un libellé : à l'encre. Le montant, lui, est un chiffre. */
.pr-earning-path { grid-column: 2; grid-row: 1; font-size: 13px; line-height: 1.5; font-weight: 700; color: var(--ink); }
/* min-width : empilés au téléphone, les deux montants gardent la même colonne. */
.pr-earning-amount { grid-column: 1; grid-row: 1 / span 2; min-width: 4ch; font-family: var(--font-display); font-size: var(--type-h2); line-height: var(--type-h2-lh); font-weight: var(--weight-display); color: var(--brand-on-surface); font-variant-numeric: tabular-nums; white-space: nowrap; }
.pr-earning-note { grid-column: 2; grid-row: 2; font-size: 13px; line-height: 1.5; color: var(--ink-muted); }

/* Sous 1280 px la colonne du héros ne tient plus quatre cartes lisibles : deux
   rangées de deux, la carte redevient une ligne (le chiffre à gauche) et le
   filet, qui ne relierait plus rien, se retire. */
@media (max-width: 1279.98px) {
  .pr-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: 1fr; }
  .pr-card { display: grid; grid-template-columns: auto minmax(0, 1fr); align-content: start; align-items: baseline; gap: var(--space-1) var(--space-6); padding: var(--space-7) var(--space-8) var(--space-6); }
  .pr-step-num { grid-row: span 2; font-size: var(--type-h2); line-height: var(--type-h2-lh); letter-spacing: var(--type-h2-ls); }
  .pr-step-label { margin-top: 0; padding-top: 0; }
  .pr-step-num::after { content: none; }
  .pr-step-glyph { display: none; }
}
@media (max-width: 600px) {
  .pr-steps, .pr-earnings { grid-template-columns: minmax(0, 1fr); }
}

/* Orange is the interaction cue: blue remains the selected/brand state,
   while a pointer preview is unmistakably actionable. */
#o-service-chips .chip:hover,
#o-service-chips .chip:focus-visible {
  border-color: var(--nota-orange-400);
  color: var(--nota-orange-400);
  background: color-mix(in srgb, var(--nota-orange-400) 12%, var(--surface));
}
#o-service-chips .chip:hover .chip-svc-badge,
#o-service-chips .chip:focus-visible .chip-svc-badge {
  border-color: var(--nota-orange-400);
}
#o-service-chips .chip:hover .svc-ic,
#o-service-chips .chip:focus-visible .svc-ic {
  color: var(--nota-orange-400);
}
/* The claim form's payoff: the shareable link, ready to copy. */
/* Le bouton ne TRAVERSE plus la colonne (2026-09-07, même retour que la
   feuille de réservation) : une action large de 480 px pour deux mots se lit
   comme une bande, pas comme une cible. Il se dimensionne sur son libellé et
   s'aligne sur le bord gauche des champs qu'il conclut. */
#partner-form .btn-lg { margin-top: var(--space-6); width: auto; min-width: 200px; }
.partner-success { margin-top: var(--space-5); padding: var(--space-5) var(--space-6); border: 1px solid var(--accent-blue); border-radius: var(--radius); background: var(--surface-inset); }
.partner-success[hidden] { display: none; }
/* Le chemin d'un menu, écrit sous le lien qu'il faut y coller. Deux lignes,
   un nom d'application en tête, des chevrons entre les étapes : rien à
   cliquer ici, c'est une instruction, pas un contrôle. */
.sub-howto { list-style: none; margin: var(--space-4) 0 0; padding: 0; display: grid; gap: var(--space-2); }
.sub-howto li { font-size: 12px; line-height: 1.5; color: var(--ink-muted); }
.sub-howto-app { display: inline-block; margin-right: var(--space-3); font-weight: 800; color: var(--ink); }
.sub-howto-sep { margin: 0 4px; color: var(--border-strong); }

/* The ready-to-send message under the claimed link: a quiet inset block the
   partner reads once, then its own copy button. */
.partner-msg { margin-top: var(--space-6); padding-top: var(--space-5); border-top: 1px solid var(--border); }
.partner-results { margin-top: var(--space-8); padding-top: var(--space-6); border-top: 1px solid var(--border); }
.partner-results > .h-sub { margin: 0 0 var(--space-4); }
.partner-results-flow { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); margin: 0 0 var(--space-4); padding: 0; list-style: none; color: var(--ink-muted); font-size: var(--type-eyebrow); }
.partner-results-flow li { display: flex; align-items: center; gap: var(--space-4); }
.partner-results-flow li:not(:last-child)::after { content: '→'; color: var(--accent-blue); }
.partner-results form { display: grid; gap: var(--space-3); }
.partner-results form[hidden] { display: none; }
.partner-results form .btn { justify-self: start; }
.partner-results-metrics { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-5); margin: var(--space-5) 0; }
.partner-results-metrics[hidden] { display: none; }
.partner-results-metrics > div { min-width: 0; }
.partner-results-metrics dt { color: var(--ink-muted); font-size: var(--type-eyebrow); }
.partner-results-metrics dd { margin: var(--space-2) 0 0; font-family: var(--font-mono); font-weight: 700; color: var(--ink); overflow-wrap: anywhere; }
.partner-msg-text { margin: var(--space-3) 0 var(--space-4); padding: var(--space-4) var(--space-5); font-size: 13px; line-height: 1.5; color: var(--ink); background: var(--surface-inset); border-radius: var(--radius-sm); white-space: pre-wrap; overflow-wrap: anywhere; }
/* A copy button that just worked: the label reads « Copié ✓ » in the ok ink for a beat (app.js flashCopied). */
.btn.is-copied { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 45%, transparent); }
.partner-link-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
/* user-select: all — un clic prend tout le lien, même là où le presse-papiers
   n'existe pas (le bouton « Copier » le dit alors, sans prétendre avoir copié). */
.partner-link-row code { min-width: 0; font-family: var(--font-mono); font-size: 13px; padding: 6px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface); overflow-wrap: anywhere; user-select: all; transition: border-color var(--motion-fast) var(--ease-ui); }
.partner-link-row code:hover { border-color: var(--action-ink); }
.pr-claim .partner-active-code { margin: var(--space-5) 0 var(--space-7); font-family: var(--font-mono); font-size: clamp(20px, 2.2vw, 26px); font-weight: 700; letter-spacing: .03em; color: var(--accent-blue); overflow-wrap: anywhere; }
/* « Ce qui manque encore » : une ligne tenue sous les champs, qui passe à
   l'encre vivante quand tout est prêt. */
.partner-next-step { padding-left: var(--space-5); border-left: 2px solid var(--border-strong); line-height: 1.6; transition: border-color var(--motion-ui) var(--ease-ui), color var(--motion-ui) var(--ease-ui); }
.partner-next-step[data-ready='true'] { border-color: var(--accent-warm); color: var(--brand-on-surface); }
.pr-claim .partner-rappel-line { margin: var(--space-8) 0 0; line-height: 1.6; }
.pr-claim .partner-pending-to { font-size: 14px; line-height: 1.6; overflow-wrap: anywhere; }
/* Le message prêt à envoyer garde sa taille de lecture dans le panneau. */
.pr-claim .partner-msg-text { margin: var(--space-3) 0 var(--space-4); font-size: 13px; }
#partner-pending-email { display: block; color: var(--ink); }
#partner-pending { border-color: var(--brand); }
#partner-email-edit { min-height: 44px; margin-top: var(--space-4); }
/* L'aperçu du lien est une mention vivante : l'encre des états, lisible aussi
   sur la nuit (le bleu de marque nu y tombe sous AA). */
#partner-code-preview[data-state='ok'] { color: var(--brand-on-surface); }

/* LE MOUVEMENT DE LA PORTE (2026-09-20) — quatre gestes à elle, sobres, sur les
   barreaux du registre et la seule courbe --ease-ui :
     pr-num-ink      le chiffre de chaque étape s'encre, de 1 à 4, à la suite du
                     trait d'accent que .accent-line trace au-dessus de lui ;
     pr-thread-draw  le filet de 2 px file du chiffre vers l'étape suivante ;
     pr-state-in     le bloc d'état qui apparaît dans le panneau (formulaire,
                     reçu « en attente », code réclamé, notaire) entre en
                     fondu-montée sur le barreau des panneaux : `hidden` tombe,
                     l'élément est rendu, l'animation part — aucun script ;
     pr-link-land    l'aperçu du lien se pose quand le code devient valide (il
                     ne rejoue pas à chaque frappe : l'état reste « ok »).
   Les montants s'allument UNE fois (amtGlow) : un éclat revient à son repos,
   sa durée est donc un jeton local (--pr-glow-beat), hors des trois barreaux.
   Tout vit sous « no-preference » : en mouvement réduit rien n'attend à l'état
   « from ». Les chiffres ne s'animent que sous .is-in (posé par wireReveal) :
   sans script ni IntersectionObserver ils sont simplement là. L'état FINAL de
   chaque keyframe est l'état lisible. */
@media (prefers-reduced-motion: no-preference) {
  .pr-steps.is-in .pr-step-num { animation: pr-num-ink var(--motion-enter) var(--ease-ui) both; animation-delay: calc(var(--motion-ui) + var(--reveal-i, 0) * var(--menu-stagger)); }
  .pr-steps.is-in .pr-step-num::after { animation: pr-thread-draw var(--motion-enter) var(--ease-ui) both; animation-delay: calc(var(--motion-enter) + var(--reveal-i, 0) * var(--menu-stagger)); }
  .pr-steps.is-in .pr-step-detail strong, .partner-gains.is-in .pr-earning-amount { animation: amtGlow var(--pr-glow-beat) var(--ease-ui) both; animation-delay: calc(var(--motion-enter) * 2 + var(--reveal-i, 0) * var(--menu-stagger)); }
  #partner-form:not([hidden]), #partner-pending:not([hidden]), #partner-success:not([hidden]), #partner-notary-block:not([hidden]) { animation: pr-state-in var(--motion-ui) var(--ease-ui) both; }
  #partner-code-preview[data-state='ok'] { animation: pr-link-land var(--motion-ui) var(--ease-ui) both; }
}
@keyframes pr-num-ink { from { opacity: 0; transform: translateY(var(--space-3)) scale(.9); } to { opacity: 1; transform: none; } }
@keyframes pr-thread-draw { from { transform: scaleX(0); } to { transform: none; } }
@keyframes pr-state-in { from { opacity: 0; transform: translateY(var(--space-4)); } to { opacity: 1; transform: none; } }
@keyframes pr-link-land { from { opacity: 0; transform: translateY(calc(var(--space-3) * -1)); } to { opacity: 1; transform: none; } }

/* --- Dossier ------------------------------------------------------------- */
.dossier-bar { height: 8px; background: var(--surface-inset); border-radius: var(--radius-xs); overflow: hidden; margin: 8px 0; }
.dossier-bar > span { display: block; width: 0; height: 100%; background: var(--brand); }
/* The gate line (what's left before the demand is sellable) renders inside
   the consent card — right where the gate completes (ADR 0010 §3). */
.dossier-missing { min-height: 1.5em; font-size: 13px; color: var(--ink-muted); margin-top: 8px; }
.dossier-missing[data-ready='true'] { color: var(--ok); font-weight: 700; }
/* Heading over the preparation checklist — carries the 0/N count and bar of
   the list it measures (progress, never a gate, ADR 0010 §3). */
.dossier-prep-h { display: flex; flex-direction: column; gap: 2px; padding: 6px 2px 0; }
.dossier-prep-h strong { font-size: 14px; letter-spacing: -0.01em; }
.dossier-prep-count { font-size: 13px; color: var(--ink-muted); font-variant-numeric: tabular-nums; }
/* Upload and "already sent" side by side — two channels, one row. */
.doc-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 8px; }
/* The drag hint rides the actions row (inline, zeroed stacking margin) — its
   own line cost every empty card ~20px for eight muted words. The picker's own
   stacking margin is zeroed too: the row already carries the spacing. */
.doc-actions .file-note, .doc-actions .file-field { margin-top: 0; }
/* "Transmis autrement" (ADR 0010 §4): a distinct provided-state — the ok hue
   says done, the undo keeps it reversible. */
.doc-transmis { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 8px; }
.doc-transmis-lbl { font-size: 13px; font-weight: 700; color: var(--ok); }
.consent-toggle { display: inline-flex; align-items: center; gap: 8px; margin-top: 8px; font-size: 13px; font-weight: 600; cursor: pointer; }
.consent-toggle input { width: 18px; height: 18px; accent-color: var(--brand); cursor: pointer; }
/* Dossier: price card, consent, then the document checklist. The checklist
   packs into a card GRID — several small pieces per row instead of one
   full-width line each, so 7 items don't scroll for a screen and a half. */
.dossier-list { display: flex; flex-direction: column; gap: 8px; padding: 4px 0; }
.dossier-item { display: flex; gap: 10px; align-items: flex-start; padding: var(--space-5) var(--space-6); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.dossier-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 8px; }
/* Each checklist card: name + help on top, the action (upload / already-sent,
   or the answer field) pinned to the bottom so neighbouring cards end on the
   same line whatever the length of their help text. */
.dossier-row .dossier-body { display: flex; flex-direction: column; align-self: stretch; }
.dossier-row .doc-actions, .dossier-row .doc-transmis,
.dossier-row .dossier-body > input[type='text'] { margin-top: auto; }
.dossier-row .dossier-body > .help { margin-bottom: 8px; }
.dossier-pricing { padding: var(--space-6) var(--space-7); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
/* Capped at 3 tracks: auto-fit on a wide screen spread 6 questions into one
   ragged row of uneven heights — 3×2 keeps the rows balanced and the help
   text wrapping instead of a dead right half. */
.dossier-pricing .o-criteria { margin-top: var(--space-6); display: flex; flex-direction: column; gap: var(--space-10); }
.dossier-pricing .crit-sec-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-5) var(--space-8); }
@media (max-width: 1100px) { .dossier-pricing .crit-sec-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 680px) { .dossier-pricing .crit-sec-grid { grid-template-columns: minmax(0, 1fr); } }
/* Les questions du notaire en SECTIONS (2026-09-05) : trois temps déclarés par
   le domaine — le prêt, l'immeuble, la signature. La pile des sections est
   verticale ; c'est DANS une section que les questions s'alignent sur la grille
   à deux colonnes (audit 2.15 : l'ordre de lecture est l'ordre du DOM, jamais
   du multicol qui coulait la question 3 sous la question 1). Les lignes
   s'alignent en haut, et le grand contrôle du déplacement traverse la grille. */
#o-criteria { display: flex; flex-direction: column; gap: var(--space-6); }
.crit-sec-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-6) var(--space-9); align-items: start; }
@media (max-width: 560px) { .crit-sec-grid { grid-template-columns: minmax(0, 1fr); } }
#o-criteria .crit-row { margin: 0; }
.crit-row--wide { grid-column: 1 / -1; }
/* Une question seule sur sa ligne PREND la ligne (retour du propriétaire,
   2026-09-05 : « avoid blank space ») : trois questions dans une grille à deux
   colonnes laissaient une demi-carte vide à droite de la troisième, et une
   section qui n'en pose qu'une (« L'immeuble ») laissait la moitié du cadre
   nu. Le dernier enfant d'un rang impair traverse la grille. */
.crit-sec-grid > .crit-row:last-child:nth-child(odd) { grid-column: 1 / -1; }
/* Et un rang qui PORTE TROIS CHOIX prend la ligne quoi qu'il arrive : dans une
   demi-largeur, « Approbation bancaire » s'empilait en trois lignes à côté d'un
   champ d'une seule — deux cellules d'une même paire, l'une trois fois plus
   haute que l'autre (retour du propriétaire, 2026-09-06). Sur la ligne entière
   les trois choix se rangent côte à côte, et la paire au-dessus est faite de
   deux rangs de même taille. Le tri du DOM (renderCriteriaSections) fait
   descendre ces rangs sous les compacts, donc aucune demi-cellule ne reste
   vide au-dessus d'eux. */
.crit-sec-grid > .crit-row[data-span='row'] { grid-column: 1 / -1; }
/* Et le rang compact resté SEUL DEVANT une bande prend la ligne à son tour
   (retour du propriétaire, 2026-09-07 : « enlever tous les espaces blancs ») :
   « Prêteur hypothécaire » gardait un demi-cadre nu à sa droite parce que la
   question suivante traversait déjà la grille — la règle du dernier rang impair
   ne voyait que la FIN de la section. Le filet CSS tient même là où rien n'est
   mesurable (dialogue fermé, impression) ; la passe mesurée, elle, évite le cas
   en faisant d'abord tenir les réponses sur une ligne. */
.crit-sec-grid > .crit-row:nth-child(odd):has(+ .crit-row[data-span='row']),
.crit-sec-grid > .crit-row:nth-child(odd):has(+ .crit-row--wide) { grid-column: 1 / -1; }
/* Et la dernière rangée de rangs compacts se remplit, quel que soit le nombre
   de colonnes : packCriteriaGrids compte les pistes réelles et dit ici combien
   il en reste à couvrir (le carnet du dossier en dessine trois, la feuille
   deux). Deux valeurs suffisent : aucune grille du produit ne va plus loin. */
.crit-sec-grid > .crit-row[data-fill='2'] { grid-column: span 2; }
.crit-sec-grid > .crit-row[data-fill='3'] { grid-column: span 3; }
/* Et elle OCCUPE la ligne au lieu de s'y perdre : les réponses en boutons
   s'étalent sur toute la largeur (flex: 1 1 auto), et une liste s'allonge
   jusqu'à une largeur de lecture — un contrôle de 320 px suivi d'un demi-cadre
   nu était le vide le plus visible de la grille. */
@media (min-width: 561px) {
  .crit-sec-grid > .crit-row:last-child:nth-child(odd) > .nselect,
  .crit-sec-grid > .crit-row:nth-child(odd):has(+ .crit-row[data-span='row']) > .nselect,
  .crit-sec-grid > .crit-row:nth-child(odd):has(+ .crit-row--wide) > .nselect,
  .crit-sec-grid > .crit-row[data-fill] > .nselect { max-width: 420px; }
}
/* Les écrans qui portent des SECTIONS ne portent plus leur propre cadre : deux
   boîtes emboîtées mangeaient 30 px de largeur de chaque côté et donnaient au
   dialogue trois niveaux de bordure. Le titre de l'écran coiffe les cartes. */
#o-criteria-step, .book-step-offer { padding: 0; border: 0; background: none; }
/* Une section est une CARTE, pas un simple filet (retour du propriétaire,
   2026-09-05 : « mieux découpler les sections, ajouter des petites marges »).
   Un trait à gauche ne suffisait pas : le titre de la section suivante venait
   coller à la dernière réponse de la précédente, et les trois temps se lisaient
   comme une seule colonne. Cadre + coin carré + air autour, et 20 px entre les
   cartes. Le FOND reste celui du dialogue : les contrôles à l'intérieur
   (segments, listes, volets) portent déjà --surface-inset, et remplir la carte
   de la même teinte les effacerait. */
.crit-sec, .offer-sec {
  display: flex; flex-direction: column; gap: var(--space-6);
  padding: var(--space-7) var(--space-8) var(--space-8);
  border: 1px solid var(--border); border-radius: var(--radius);
}
/* L'écran 3 emprunte le même registre (voir index.html) : trois cartes — le
   montant, le marché, le devis — au lieu de dix blocs à la file. Ses contenus
   se serrent un cran de plus que des questions : ce sont des lignes de lecture,
   pas des contrôles à viser. */
.offer-sec { gap: var(--space-5); }
.book-step-offer { gap: var(--space-8); }
/* Les boîtes intérieures se sont FONDUES dans leur carte : le marché et le
   devis portaient chacun leur propre cadre + fond, ce qui faisait deux cadres
   l'un dans l'autre dès qu'ils sont entrés en section. La carte est le cadre. */
.offer-sec > .day-market, .offer-sec > .devis {
  margin: 0; padding: 0; border: 0; background: none; border-radius: 0;
}
.offer-sec > .day-market .day-bids { margin: var(--space-4) 0 0; }
/* L'en-tête est une bande : le titre, son compte, sa raison d'être — puis un
   filet qui la sépare des questions. */
/* L'en-tête est une BANDE, pas un titre suivi d'un filet (2026-09-06) : elle
   court d'un bord à l'autre de la carte, sur sa propre teinte, et coiffe le
   sujet comme l'en-tête d'un tableau coiffe sa colonne. Un titre posé DANS le
   cadre, à la même distance des questions que les questions entre elles, ne
   disait pas où un sujet commençait. Les marges négatives valent le padding de
   .crit-sec — la bande est le haut de la carte, pas un bloc posé dedans. */
.crit-sec-h {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-5);
  margin: calc(-1 * var(--space-7)) calc(-1 * var(--space-8)) 0;
  padding: var(--space-5) var(--space-8);
  background: var(--surface-inset);
  border-bottom: 1px solid var(--border);
  border-radius: var(--radius) var(--radius) 0 0;
}
/* Repliée, la bande EST la carte : plus de trait sous elle, rien en dessous. */
.crit-sec[data-fold='true'] > .crit-sec-h { border-bottom-color: transparent; border-radius: var(--radius); }
.crit-sec[data-fold='true'] > .crit-sec-grid,
.crit-sec[data-fold='true'] > .crit-more { display: none; }
.crit-sec[data-fold='true'] { padding-bottom: 0; gap: 0; }
/* Le chevron du pli : muet, à droite du compte, tourné vers le bas quand la
   section est ouverte. Il porte le nom de sa section en aria-label — le titre
   est à deux centimètres, il n'a pas de mot à ajouter. */
.crit-sec-fold {
  appearance: none; border: 0; background: none; padding: 0; margin-left: var(--space-3);
  width: 24px; height: 24px; display: inline-grid; place-items: center; flex: none;
  color: var(--ink-muted); cursor: pointer; border-radius: var(--radius-xs);
  transition: color var(--motion-fast), background-color var(--motion-fast);
}
.crit-sec-fold:hover { color: var(--ink); background: var(--action-tint); }
.crit-sec-fold .crit-sec-chev { transition: transform var(--motion-fast) var(--ease-ui); }
.crit-sec-fold[aria-expanded='false'] .crit-sec-chev { transform: rotate(-90deg); }
/* Le compte cesse de pousser le chevron au bout de la ligne : c'est LUI qui
   ferme la bande. */
.crit-sec-h:has(.crit-sec-fold) .crit-sec-n { margin-left: auto; }
/* Le titre de section portait 14px/700 quand la question en dessous porte
   13,5px/600 : un cheveu d'écart, donc aucune hiérarchie — l'œil ne trouvait
   pas où un sujet commençait (retour du propriétaire, 2026-09-06 : « comprendre
   d'un coup d'œil que ceci se rapporte à tel sujet »). Un vrai cran au-dessus. */
.crit-sec-t { font-size: 15px; font-weight: 800; color: var(--ink); letter-spacing: -0.01em; }
/* La pastille du sujet : même construction que celle des actes (glyphe au trait
   dans un carré à filet), un cran plus petite — c'est un en-tête, pas une
   cible. Elle passe à la marque quand la section est complète, si bien que
   l'avancement se lit sur la colonne des pastilles sans lire un seul compte. */
.crit-sec-ic {
  width: 28px; height: 28px; flex: none; display: inline-grid; place-items: center;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-inset); color: var(--ink-muted);
  transition: color var(--motion-fast), border-color var(--motion-fast), background var(--motion-fast);
}
.crit-sec:has(.crit-sec-n[data-state='done']) .crit-sec-ic {
  color: var(--brand); border-color: color-mix(in srgb, var(--brand) 45%, var(--border));
  background: transparent;
}
/* La raison d'être de la section prend toute la ligne suivante : elle explique,
   elle ne se dispute pas la première ligne avec le compte. Elle s'aligne sous
   le TITRE, pas sous la pastille : le bloc d'en-tête se lit alors comme un
   seul objet au lieu de deux lignes qui commencent à deux endroits. */
/* Elle RIDE la ligne du titre (2026-09-07) : une ligne entière par section
   pour se présenter, c'était trois lignes dépensées avant la première question
   — et l'écran s'ouvrait sur des bandes plutôt que sur des réponses à donner.
   Elle ne bascule sous le titre que si la largeur lui manque (flex-basis), et
   le compte reste collé au bord droit par sa marge automatique. */
.crit-sec-aide { flex: 1 1 240px; min-width: 0; margin: 0; font-size: 12px; color: var(--ink-muted); }
/* Sur un téléphone elle ne tient jamais à côté du titre : elle repasse SOUS la
   bande — mais après le compte et le chevron, sinon c'est le chevron qui tombe
   sur une troisième ligne et la bande coûte plus cher qu'avant. */
@media (max-width: 560px) {
  .crit-sec-aide { order: 1; flex: 1 0 100%; margin-top: var(--space-1); }
}
/* Le compte de la section — le même vocabulaire et les mêmes couleurs que le
   compte de l'étape : ambre tant qu'on attend, marque une fois complet. */
.crit-sec-n {
  margin-left: auto; min-width: 18px; padding: 1px 5px; border-radius: var(--radius-xs);
  background: transparent; border: 1px solid var(--warn);
  font-size: 11.5px; font-weight: 700; color: var(--warn); text-align: center;
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.crit-sec-n[data-state='done'] { color: var(--brand); background: transparent; border-color: var(--brand); }
/* Les précisions d'une section, repliées à côté du cas qu'elles précisent. */
.crit-sec > .crit-more { margin: var(--space-1) 0 0; }
.crit-sec > .crit-more .crit-sec-grid { padding: var(--space-6) var(--space-7) var(--space-4); }
/* Le volet dit combien de questions il cache. */
.crit-more-n {
  margin-left: 7px; min-width: 16px; padding: 1px 5px; border-radius: var(--radius-xs);
  background: var(--surface-inset); color: var(--ink-muted);
  font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums;
}
/* Ce qu'une réponse change à la liste des documents, sous la réponse. Ligne
   RÉSERVÉE dès la première peinture et masquée par `visibility` (registre ADR
   0039) : répondre, se raviser, répondre à nouveau ne déplace jamais la
   question suivante. */
.crit-effet { font-size: 12px; color: var(--ink-muted); }
.crit-effet[data-on='false'] { visibility: hidden; }
.crit-effet-k { font-weight: 600; color: var(--brand); }
/* The card's payoff — the determined price — separated from the questions and
   said a size louder, not buried in the bottom-left corner. */
.dossier-price { margin-top: var(--space-5); padding-top: var(--space-4); border-top: 1px dashed var(--border); font-weight: 700; color: var(--brand); font-size: 15px; font-variant-numeric: tabular-nums; }
/* Profile: a top row of at-a-glance / set-once cards (offers · coordinates ·
   notifications) that auto-fit across the width, then a full-width documents
   work area below — no tall-thin void, honest use of the horizontal space. */
.profil-stack { display: flex; flex-direction: column; gap: 10px; }
/* Every section is a full-width band whose content lays out in a grid that
   fills the width (auto-fit) — no empty right half, no ragged inter-card void. */
/* Four equal tracks: the profile's four fields make ONE row on a wide screen —
   the whole Coordonnées band is head + a single line of inputs. Short values
   (code postal) simply breathe in theirs. */
.profil-fields { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px 16px; align-items: end; }
@media (max-width: 1000px) { .profil-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .profil-fields { grid-template-columns: 1fr; } }
.profil-fields .form-row { margin: 0; }
/* Fill the cell: capped at 460px the inputs left ~100px of dead track beside
   each one, which read as a broken grid rather than as breathing room. */
.profil-fields .form-row input { width: 100%; }
.profil-switches { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 22px; max-width: 1060px; }
@media (max-width: 900px) { .profil-switches { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 700px) { .profil-switches { grid-template-columns: 1fr; } }
.profil-card { padding: 12px 16px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); display: flex; flex-direction: column; gap: 6px; }
.profil-card-title { font-size: 15px; font-weight: 700; color: var(--ink); }
/* Iconed section header so the bands are easy to tell apart at a glance. The
   caption (.profil-card-sub) rides the same row, wrapping under the title only
   when the width runs out — a full line per card was pure chrome. */
.profil-card-head { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 10px; }
.profil-card-sub { flex: 1 1 320px; min-width: 0; margin: 0; font-size: 12.5px; line-height: 1.45; color: var(--ink-muted); }
.profil-card-ic { display: grid; place-items: center; width: 26px; height: 26px; flex: none; border-radius: var(--radius-sm); background: var(--surface-inset); color: var(--brand); }
.profil-card-ic svg { display: block; }
/* The card is a flex column with its own gap — zero the children's stacking
   margins so field/switch spacing isn't doubled (the source of the void). */
.profil-card .form-row { margin-bottom: 2px; }
.profil-card .form-row label.lbl { margin-bottom: 6px; }
.profil-card .switch-row { padding: 4px 0; justify-content: flex-start; gap: 12px; }
.profil-card .help { margin-top: 0; }
/* Mes offres — the client's posted offers with live status. */
.my-offer:hover, .my-offer:focus-visible { border-color: var(--action-ink); outline: none; }
/* Documents inside the profile: upload / remove / mark-validated. */
.profil-doc-chips { margin: 2px 0 6px; }
/* Flex (not grid) so the LAST row's cards grow to fill the width — no empty
   right-side slots when the document count doesn't divide evenly. */
.profil-doc-list { display: block; }
/* The checklist collapses behind its progress line. .doc-rows carries the wrap
   that .profil-doc-list used to, so rows still pack 2-up and 3-up as they widen. */
.doc-rows { display: flex; flex-wrap: wrap; gap: var(--space-5); align-items: stretch; padding-top: var(--space-5); }
.profil-doc-list .doc-row { flex: 1 1 300px; }
.doc-disclose { border: 0; }
/* The whole progress line is the control, so it gets the thumb-sized target and
   the chevron the rest of the app uses for the same bargain. */
.doc-summary {
  display: flex; align-items: center; gap: var(--space-5);
  min-height: 44px; padding: var(--space-2) 0; cursor: pointer; list-style: none;
  border-radius: var(--radius-sm);
}
.doc-summary::-webkit-details-marker { display: none; }
.doc-summary .doc-progress { flex: 1; margin-bottom: 0; }
.doc-summary::after {
  content: ''; flex: none; width: 9px; height: 9px; margin-right: var(--space-2);
  border-right: 2px solid var(--ink-muted); border-bottom: 2px solid var(--ink-muted);
  transform: rotate(45deg) translate(-2px, -2px); transition: transform var(--motion-fast) var(--ease-ui);
}
.doc-disclose[open] > .doc-summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.doc-summary:hover::after { border-color: var(--ink); }
.doc-summary:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--focus-ring); }
/* Documents progress header: labelled bar, full-width above the checklist. */
.doc-progress { flex: 1 1 100%; display: flex; flex-direction: column; gap: 6px; margin-bottom: 2px; }
.doc-count { font-size: 12.5px; font-weight: 600; color: var(--ink-muted); }
.doc-count[data-complete='true'] { color: var(--ok); }
.doc-bar { height: 6px; background: var(--surface-inset); border-radius: var(--radius-xs); overflow: hidden; }
.doc-bar span { display: block; height: 100%; background: var(--brand-bright); border-radius: var(--radius-xs); transition: width var(--motion-ui) var(--ease-ui); }
.doc-progress[data-complete='true'] .doc-bar span { background: var(--ok); }
/* First-time empty state (Mes offres with no offers). */
/* Mes offres — four facts per offer, on one axis. Full-width bands spent about
   1500px of horizontal space per row saying four short things, and made seven
   offers an 800px wall. */
.my-offers { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.my-offers th {
  text-align: left; padding: 0 10px 6px;
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .02em;
  color: var(--ink-muted); border-bottom: 1px solid var(--border);
}
.my-offers td { padding: 9px 10px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.my-offers tbody tr:last-child td { border-bottom: 0; }
.my-offers .c-acte { font-weight: 600; min-width: 150px; }
.my-offers .c-date { width: 24%; min-width: 120px; }
.my-offers .c-montant { width: 16%; min-width: 92px; text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.my-offers .c-statut { width: 14%; min-width: 96px; }
/* The date is a door to that day on the carnet: a real button, styled as a link. */
.my-offer-day { display: block; padding: 0; border: 0; background: none; font: inherit; font-weight: 600; color: var(--brand); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; text-align: left; }
.my-offer-day:hover { color: var(--ink); }
.my-offer-day:focus-visible { outline: 2px solid var(--action-ink); outline-offset: 2px; border-radius: var(--radius-xs); }
.my-offer-rel { display: block; margin-top: 1px; font-size: 12px; color: var(--ink-muted); }
/* Under each row: the next step, the agenda links, and what a notary sent back. */
.my-offer-detail td { padding: 4px 10px 12px; }
.my-offer-next { display: flex; flex-wrap: wrap; gap: 4px 8px; font-size: 12.5px; line-height: 1.45; }
.my-offer-next-k { font-weight: 700; color: var(--ink-muted); text-transform: uppercase; font-size: 10.5px; letter-spacing: .03em; align-self: center; }
.my-offer-next-v { color: var(--ink); }
.my-offer-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
/* Le reçu du client : deux lignes et un total, dans le registre carré de la
   carte. Il paraît une fois l'acte réglé, au-dessus de l'évaluation. */
.my-offer-receipt { margin-top: 10px; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-inset); }
.my-offer-receipt-h { font-weight: 700; color: var(--ink-muted); text-transform: uppercase; font-size: 10.5px; letter-spacing: .03em; margin-bottom: 6px; }
.my-offer-receipt-lines { display: grid; grid-template-columns: 1fr auto; gap: 3px 12px; margin: 0; font-size: 12.5px; }
.my-offer-receipt-lines dt { color: var(--ink-muted); margin: 0; }
.my-offer-receipt-lines dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; color: var(--ink); }
.my-offer-receipt-lines .my-offer-receipt-total { font-weight: 700; color: var(--ink); border-top: 1px solid var(--border); padding-top: 4px; margin-top: 2px; }
/* ADR 0035 — la carte a été refusée au moment de réserver la somme. Un bloc
   qui se voit (filet rouge, fond teinté) sans crier : rien n'est perdu, mais
   il y a un geste à poser avant la signature. */
.my-offer-carte {
  margin-top: var(--space-4); padding: var(--space-4) var(--space-5);
  border: 1px solid var(--danger); border-left-width: 3px; border-radius: var(--radius-sm);
  background: var(--surface-inset);
}
.my-offer-carte-h { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--danger); }
.my-offer-carte-t { margin: var(--space-2) 0 0; font-size: 13px; line-height: 1.5; color: var(--ink); }
/* Mise en relation (ADR 0010 §4): whom to contact once the offer is retained. */
.my-offer-contact { margin-top: 8px; font-size: 13px; line-height: 1.5; }
.my-offer-contact-mail { color: var(--brand); font-weight: 600; }
/* « Votre notaire » (ADR 0033): heading, name line, then one row per way to
   reach them — tel:, mailto:, the étude on a map. Facts only, square register. */
.my-offer-contact-h { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-muted); }
.my-offer-contact-name { margin-top: var(--space-2); font-size: 14px; }
.my-offer-contact-etude { color: var(--ink-muted); }
.my-offer-contact-rows { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-8); margin-top: var(--space-2); }
.my-offer-contact-row {
  display: inline-flex; align-items: center; gap: 6px; min-height: 28px;
  font-size: 13px; font-weight: 600; color: var(--brand); text-decoration: none; overflow-wrap: anywhere;
}
.my-offer-contact-row:hover { text-decoration: underline; }
.my-offer-contact-tel { font-variant-numeric: tabular-nums; }
.my-offer-contact-addr { font-weight: 500; }
/* Unread notary messages beside the status: a door to the thread, a filled
   square badge while there is something to read, nothing when there is not. */
.my-offer-unread {
  display: inline-flex; align-items: center; margin-left: var(--space-3); padding: 2px 8px;
  border: 0; font: inherit; font-size: 11px; font-weight: 800; white-space: nowrap; cursor: pointer;
  border-radius: var(--radius-sm); background: var(--brand); color: var(--brand-ink);
}
.my-offer-unread:empty { display: none; }
.my-offer-unread:focus-visible { outline: 2px solid var(--action-ink); outline-offset: 2px; }
/* A notary's proposition / document request: the block that asks for a decision. */
.my-offer-prop, .my-offer-demande {
  margin-top: 10px; padding: 10px 12px; border-radius: var(--radius);
  border: 1px solid var(--brand); border-left-width: 4px; background: var(--surface-inset);
}
.my-offer-prop[data-status='acceptee'] { border-color: var(--ok); }
/* Settled blocks recede through muted ink, never element opacity. */
.my-offer-prop[data-status='refusee'], .my-offer-demande[data-fournie='true'] { border-color: var(--border); color: var(--ink-muted); }
.my-offer-prop-text { font-size: 13.5px; line-height: 1.45; }
.my-offer-prop-msg { margin: 6px 0 0; font-size: 12.5px; color: var(--ink-muted); font-style: italic; }
.my-offer-prop-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.my-offer-prop-state { margin-top: 6px; font-size: 12.5px; font-weight: 700; color: var(--ink-muted); }
.my-offer-prop-state.is-done { color: var(--ok); }
.my-offer-status {
  display: inline-block; padding: 2px 9px; border-radius: var(--radius-sm);
  border: 1px solid var(--border); color: var(--ink-muted);
  font-size: 11px; font-weight: 700; white-space: nowrap;
}
.my-offer-status[data-status='approved'] { color: var(--ok); border-color: var(--ok); }
.my-offer-status[data-status='pending'] { color: var(--brand); border-color: var(--brand); }
.my-offer-status[data-status='expired'] { color: var(--ink-muted); border-style: dashed; }
/* Offers whose date has passed are present, never diluting the live list. */
.my-offers-past { margin-top: 6px; }
.my-offers-past-sum { padding: 8px 0; font-size: 12.5px; color: var(--ink-muted); cursor: pointer; }
.my-offers-past tbody tr { color: var(--ink-muted); }

/* Below this a table cannot hold four columns without wrapping the act name to
   three lines, so each row becomes a card. The status pill gets its OWN row and
   may wrap: pinned beside the act name it forced the card past a 320px screen
   ("Ouverte — en attente d’un notaire" is 200px that must never be cut). */
@media (max-width: 860px) {
  .my-offers, .my-offers tbody, .my-offers tr, .my-offers td { display: block; width: auto; }
  .my-offers thead { display: none; }
  .my-offers tbody { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 8px; }
  .my-offers tbody tr {
    display: grid; grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: 'acte acte' 'date montant' 'statut statut';
    gap: 4px 10px; align-items: center;
    padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius);
  }
  .my-offers td { padding: 0; border: 0; min-width: 0; }
  /* The detail band joins its row's card on a phone (one card per offer). */
  .my-offers tbody tr.my-offer { border-bottom: 0; border-radius: var(--radius) var(--radius) 0 0; }
  .my-offers tbody tr.my-offer-detail { display: block; margin-top: -8px; padding: 0 12px 10px; border: 1px solid var(--border); border-top: 0; border-radius: 0 0 var(--radius) var(--radius); }
  .my-offers .c-acte { grid-area: acte; }
  .my-offers .c-statut { grid-area: statut; justify-self: start; }
  .my-offers .c-date { grid-area: date; }
  .my-offers .c-montant { grid-area: montant; }
  .my-offer-status { white-space: normal; }
}
@media (max-width: 560px) { .my-offers tbody { grid-template-columns: minmax(0, 1fr); } }
@media (pointer: coarse) { .my-offers-past-sum { min-height: 44px; display: flex; align-items: center; } }

/* Empty states are one compact row — the pitch left, the CTA right. The tall
   centered block spent ~250px of band height on one sentence and a button. */
.profil-empty { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 18px; padding: 2px 0; }
.profil-empty-text { margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--ink-muted); max-width: 64ch; }
.profil-empty .btn { flex: none; }
.profil-empty-copy { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.profil-empty-copy .help { margin: 0; }
/* Parrainage — the claimed code, big enough to read out loud; the link row
   reuses .partner-link-row from the Partenaires pane. */
.parr-code-row { display: flex; align-items: baseline; gap: 10px; }
.parr-code-lbl { font-size: 12px; font-weight: 600; color: var(--ink-muted); }
.parr-code { font-family: var(--font-mono); font-size: 18px; letter-spacing: 0.06em; color: var(--ink); }
.doc-row { border: 1px solid var(--border); border-radius: var(--radius); padding: 10px 12px; display: flex; flex-direction: column; gap: 5px; background: var(--surface); }
/* Push the control to the bottom so every card in a row ends on the same line,
   whatever the length of its help text. */
.doc-row > .file-field, .doc-row > input[type='text'] { margin-top: auto; }
.doc-row[data-done='true'] { border-color: var(--brand); }
.doc-row-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.doc-row-name { font-weight: 600; font-size: 13.5px; }
.doc-valid { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--ink-muted); white-space: nowrap; cursor: pointer; }
.doc-valid input { accent-color: var(--brand); }
.doc-file { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: 12.5px; color: var(--ink-muted); }
.doc-file-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The ✓ only shows once the item is actually provided — a blue check on
   every empty row made 0/8 read as done. */
.dossier-check { flex: none; margin-top: 2px; width: 18px; height: 18px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); display: grid; place-items: center; color: transparent; font-weight: 800; font-size: 12px; }
.dossier-check[data-on='true'] { background: transparent; color: var(--brand); border-color: var(--brand); }
.dossier-body { flex: 1; min-width: 0; }
.dossier-name { font-weight: 600; font-size: 13.5px; }
.dossier-item .help { margin-top: 2px; }
.dossier-item input[type='text'] { width: 100%; margin-top: 8px; }
.dossier-item[data-done='true'] .help { display: none; }
.dossier-item[data-done='true'] .dossier-name { color: var(--ink-muted); }
/* Themed file picker — hides the raw OS "Choose File" chrome. */
.file-field { display: inline-flex; align-items: center; gap: 8px; margin-top: 8px; cursor: pointer; }
input.file-native { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; padding: 0; }
/* Square like every other action button (owner, 2026-08-27: « make it more
   square ») — the shared radius token, never a pill; pills stay for chips. */
.file-cta { display: inline-flex; align-items: center; padding: 5px 12px; border-radius: var(--radius); border: 1.5px solid var(--border-strong); background: var(--surface); color: var(--ink-muted); font-weight: 600; font-size: 12.5px; transition: border-color var(--motion-fast), color var(--motion-fast); }
.file-field:hover .file-cta { border-color: var(--action-ink); color: var(--ink); }
.file-native:focus-visible + .file-cta { outline: 2px solid var(--ring); outline-offset: 2px; }
.file-note { font-size: 12px; color: var(--ink-muted); margin-top: 6px; }
/* A refusal (format the notary could not open, oversize) is explained IN
   PLACE, in the danger hue — nothing is saved, nothing else moves. */
.file-error { font-size: 12.5px; font-weight: 600; color: var(--danger); margin-top: 6px; }
/* The whole checklist row is a drop target while a file hovers it. */
.dossier-item[data-drop='true'], .doc-row[data-drop='true'] { border-color: var(--brand); background: var(--surface-inset); }
/* The drag affordance is desktop prose — touch has no drag to speak of. */
@media (max-width: 720px), (pointer: coarse) { .file-hint { display: none; } }

/* --- Model / footer sections -------------------------------------------- */
.section { padding: clamp(24px, 4vw, 40px) 0; border-top: 2px solid var(--brand); }
.section h2 { margin-bottom: 8px; }
.cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 20px; }
@media (max-width: 780px) { .cards { grid-template-columns: 1fr; } }
.card { border: 1px solid var(--border); border-radius: var(--radius-lg); padding: var(--space-9); background: var(--surface); box-shadow: var(--shadow-sm); }
.card h3 { margin-bottom: 6px; }
.card p { color: var(--ink-muted); font-size: 14px; margin: 0; }
.price { font-size: 22px; font-weight: 800; color: var(--brand); }

.note {
  border-left: 3px solid var(--warn); background: var(--surface-inset);
  padding: 12px 16px; border-radius: var(--radius); font-size: 13px; color: var(--ink-muted);
}
.note strong { color: var(--ink); }

/* --- Progressive disclosure (native <details>, token-styled) --------------
   Keeps required copy (Loi 25, business model) available but collapsed by
   default, so the booking flow isn't buried under text. */
.disclosure {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-inset); margin: 10px 0 14px;
}
.disclosure > summary {
  list-style: none; cursor: pointer; user-select: none;
  display: flex; align-items: center; gap: 8px;
  padding: 9px 12px; font-size: 12px; font-weight: 600; color: var(--ink-muted);
}
.disclosure > summary::-webkit-details-marker { display: none; }
.disclosure > summary::before {
  content: ''; width: 6px; height: 6px; flex: none;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg); transition: transform var(--motion-fast);
}
.disclosure[open] > summary::before { transform: rotate(45deg); }
.disclosure > summary:hover { color: var(--ink); }
.disclosure > summary:focus-visible {
  outline: none; border-radius: var(--radius-sm);
  box-shadow: 0 0 0 3px var(--focus-ring);
}
.disclosure-body { padding: 0 14px 14px; }
.disclosure-body p { font-size: 12px; color: var(--ink-muted); margin-top: 0; }
.disclosure-body p + p { margin-top: 8px; }

/* nota-footer:start */
/* Four navigation groups share one rail; the compact identity sits above. */
.site-footer { border-top: 1px solid var(--border, var(--line)); padding: var(--space-12) 0 var(--space-8); color: var(--ink-muted, var(--muted)); font: 13px/1.5 var(--font-sans); }
.site-footer .wrap { box-sizing: border-box; width: 100%; max-width: var(--layout-width); margin-inline: auto; padding-inline: var(--layout-gutter); }
.site-footer a { color: inherit; text-decoration: none; }
.site-footer :is(a, button):is(:hover, :focus-visible) { color: var(--action-ink, var(--ink)); text-decoration: underline; text-underline-offset: .2em; }
.site-footer :is(a, button):focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }
.footer-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-12); align-items: start; }
.footer-id { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-12); margin-bottom: var(--space-8); min-width: 0; }
.site-footer .footer-brand { --logo-tile: 24px; --lockup-tile: var(--logo-tile); display: inline-flex; align-items: center; gap: var(--lockup-badge-gap); flex: none; min-height: var(--control-height); color: var(--ink); }
.site-footer .brand-word { color: var(--ink); }
.site-footer .brand-sub { display: none; }
.footer-tag { margin: 0; max-width: 68ch; font-size: 13px; line-height: 1.55; }
.footer-col { display: flex; flex-direction: column; align-items: flex-start; gap: 0; min-width: 0; }
.footer-col-h { font-size: var(--type-eyebrow); font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--ink); margin-bottom: var(--space-2); }
.footer-col > a, .footer-col .footer-link { display: inline-flex; align-items: center; box-sizing: border-box; min-height: var(--control-height); min-inline-size: var(--control-height); max-width: 100%; padding: var(--space-2) 0; overflow-wrap: anywhere; }
/* The app's guide and privacy actions keep the same targets as links. */
.footer-col .footer-link { appearance: none; background: none; border: 0; font: inherit; color: inherit; cursor: pointer; text-align: left; }
.footer-base { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: var(--space-2) var(--space-6); margin-top: var(--space-5); padding-top: var(--space-3); border-top: 1px solid var(--border, var(--line)); font-size: 12px; }
.footer-credit { display: inline-flex; align-items: center; gap: .3em; white-space: nowrap; }
.footer-heart { display: inline-block; flex: none; width: 1.1em; height: 1.1em; color: var(--footer-heart); fill: currentColor; stroke: none; }
@media (max-width: 760px) {
  .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-10) var(--space-8); }
  .footer-id { align-items: flex-start; }
}
/* RÉSEAUX SOCIAUX : LOGOS CARRÉS REMPLIS.
   Propriétaire, 2026-09-16 : logos de marque carrés, remplis (fill),
   pas de trait. Les trois icônes partagent la même encre et la même
   taille, avec un survol qui éclaircit. */
.footer-social {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 2px;
  margin-top: 0;
}
.footer-social-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  color: var(--ink-muted, var(--muted));
  background: transparent;
  transition: color var(--motion-fast) var(--ease-ui), background-color var(--motion-fast) var(--ease-ui), transform var(--motion-fast) var(--ease-ui);
  text-decoration: none;
}
.footer-social-link:hover,
.footer-social-link:focus-visible {
  background: color-mix(in srgb, var(--action-ink, var(--ink)) 8%, transparent);
  color: var(--action-ink, var(--ink));
  transform: translateX(2px);
}
.footer-social-link:focus-visible {
  outline: 2px solid var(--action-ink, var(--ink));
  outline-offset: 2px;
}
.footer-social-link svg {
  display: block;
  width: 20px;
  height: 20px;
  fill: currentColor;
  stroke: none;
  flex: none;
}
.footer-social-label {
  font-size: 13px;
  line-height: 1.4;
}
/* Section sub-headings: "Nous écrire" and "Suivez-nous" separate the
   contact column into two scannable groups. */
.footer-col-sub {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--ink-muted, var(--muted));
  margin-top: 12px;
  margin-bottom: 2px;
}
.footer-col-sub:first-of-type {
  margin-top: 4px;
}
/* App contact actions: text links with a small prefix icon. Each row
   reads as "icon + label" so users know what they are clicking. */
.footer-contact { display: flex; flex-direction: column; align-items: stretch; gap: 2px; }
.footer-contact-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 8px;
  border-radius: var(--radius-sm);
  color: var(--ink-muted, var(--muted));
  font-size: 13px;
  line-height: 1.4;
  text-decoration: none;
  transition: color var(--motion-fast) var(--ease-ui), background-color var(--motion-fast) var(--ease-ui), transform var(--motion-fast) var(--ease-ui);
  min-height: var(--control-height);
  box-sizing: border-box;
}
.footer-contact-link:hover,
.footer-contact-link:focus-visible {
  color: var(--action-ink, var(--ink));
  background: color-mix(in srgb, var(--action-ink, var(--ink)) 8%, transparent);
  transform: translateX(2px);
}
.footer-contact-link:focus-visible {
  outline: 2px solid var(--action-ink, var(--ink));
  outline-offset: 2px;
}
.footer-contact-link svg {
  display: block;
  width: 16px;
  height: 16px;
  flex: none;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.footer-contact-link--email {
  font-weight: 500;
  color: var(--ink, inherit);
}
/* nota-footer:end */

.notary-empty-state {
  margin: 12px 0 0;
  padding: 14px 16px;
  border: 1px solid color-mix(in srgb, var(--brand) 22%, var(--border));
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--brand-tint-solid) 58%, var(--surface));
  color: var(--ink-muted);
}

/* Final phone guardrails: keep the toolbar's flexible availability track and
   let priced questionnaire choices become one readable, full-width column. */
@media (max-width: 480px) {
  .cal-toolbar-meta {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    min-width: 0;
  }
  .cal-toolbar-meta .result-count { display: none; }
  .o-criteria .crit-row:has(.seg-btn .crit-add) .seg {
    flex-direction: column;
    align-items: stretch;
  }
  .o-criteria .crit-row:has(.seg-btn .crit-add) .seg-btn {
    width: 100%;
    min-width: 0;
  }
  .o-criteria .crit-row:has(.seg-btn .crit-add) .crit-add {
    margin-left: auto;
  }
}

/* --- Toast --------------------------------------------------------------- */
.toast {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%) translateY(20px);
  background: var(--ink); color: var(--bg); padding: 12px 18px; border-radius: var(--radius);
  box-shadow: var(--shadow-lg); opacity: 0; pointer-events: none; transition: opacity var(--motion-fast), transform var(--motion-fast);
  z-index: 60; font-size: 14px; font-weight: 600; max-width: 90vw;
}

/* The SDLC story: a compact, self-contained visual that communicates the
   discipline without pretending that models or compliance are magic. */
@media (prefers-reduced-motion:reduce){.onb-modal[open],#onb-view-role.is-entering,#onb-view-steps.is-entering,#onb-view-steps.is-entering .onb-step{animation:none!important}#onb-view-steps.is-entering .onb-step{opacity:1;transform:none}}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* --- Dialog -------------------------------------------------------------- */
dialog {
  border: 1px solid color-mix(in srgb, var(--border-strong) 70%, var(--border));
  border-radius: var(--radius-lg); padding: 0;
  background: var(--surface);
  color: var(--ink); max-width: 440px; width: 92vw; box-shadow: var(--shadow-lg), inset 0 1px 0 rgb(255 255 255 / .03);
}
/* The beta details dialog carries a lot of prose — give it room to breathe. */
#beta-details-dialog { max-width: min(680px, 94vw); width: 94vw; }
/* ONE scrim for every dialog — the token plus the same soft blur. Scoped
   overrides drifted (two dialogs carried a hardcoded black): the shared shell
   owns the backdrop now. */
dialog::backdrop { background: color-mix(in srgb, var(--backdrop) 115%, rgb(0 0 0 / 0.15)); -webkit-backdrop-filter: blur(8px) saturate(.9); backdrop-filter: blur(8px) saturate(.9); }
/* Every popup is built the same way: its first child is
   <form method="dialog" class="dlg-x-form"> holding one ✕ button. The form is
   sticky against the dialog's own scroll box with height:0, so the ✕ stays
   pinned to the top-right corner while the dialog scrolls and costs no layout.
   The filled circle keeps the glyph legible over whatever slides beneath it. */
.dlg-x-form { position: sticky; top: 0; height: 0; margin: 0; z-index: 6; display: flex; justify-content: flex-end; }
.dlg-x {
  appearance: none; border: 1px solid color-mix(in srgb, var(--border-strong) 70%, var(--border)); background: var(--surface-inset);
  color: var(--ink-muted); cursor: pointer; width: 34px; height: 34px; margin: 10px 10px 0 0;
  border-radius: var(--radius); display: grid; place-items: center; flex: none;
  transition: background var(--motion-fast), border-color var(--motion-fast), color var(--motion-fast), transform var(--motion-fast);
  box-shadow: 0 1px 3px rgb(0 0 0 / .15);
}
.dlg-x:hover { background: var(--surface-hover); border-color: var(--action-accent); color: var(--ink); transform: scale(1.05); box-shadow: 0 2px 6px rgb(0 0 0 / .2); }
.dlg-x:active { transform: scale(.95); }
/* 34px is under the touch minimum — give fingers 44px without changing what a
   mouse sees. */
@media (pointer: coarse) { .dlg-x { width: 44px; height: 44px; } }
/* A modal owns the scroll. The lock must sit on <html>: the root element is
   the page's scroller, so hiding overflow on <body> alone still lets the page
   drift (and lose its place) under the wheel/touch behind the open dialog. */
html:has(dialog[open]), body:has(dialog[open]) { overflow: hidden; }
/* Staggered content entrance — dialog body children slide up in sequence so
   the modal feels like it's assembling rather than appearing as a block. */
dialog[open] .dialog-pad > *:not(.dlg-x-form),
dialog[open] .auth-body > *:not(.dlg-x-form),
dialog[open] .onb-body > *:not(.dlg-x-form) {
  animation: dialogContentIn var(--motion-ui) var(--ease-ui) both;
}
dialog[open] .dialog-pad > *:nth-child(1),
dialog[open] .auth-body > *:nth-child(1),
dialog[open] .onb-body > *:nth-child(1) { animation-delay: 60ms; }
dialog[open] .dialog-pad > *:nth-child(2),
dialog[open] .auth-body > *:nth-child(2),
dialog[open] .onb-body > *:nth-child(2) { animation-delay: 100ms; }
dialog[open] .dialog-pad > *:nth-child(3),
dialog[open] .auth-body > *:nth-child(3),
dialog[open] .onb-body > *:nth-child(3) { animation-delay: 140ms; }
dialog[open] .dialog-pad > *:nth-child(4),
dialog[open] .auth-body > *:nth-child(4),
dialog[open] .onb-body > *:nth-child(4) { animation-delay: 180ms; }
dialog[open] .dialog-pad > *:nth-child(5),
dialog[open] .auth-body > *:nth-child(5),
dialog[open] .onb-body > *:nth-child(5) { animation-delay: 220ms; }
dialog[open] .dialog-pad > *:nth-child(6),
dialog[open] .auth-body > *:nth-child(6),
dialog[open] .onb-body > *:nth-child(6) { animation-delay: 260ms; }
@keyframes dialogContentIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
/* The account-link confirmation is created after the OAuth callback. */
#oauth-link-dialog { padding: var(--pad-dialog); width: min(440px, calc(100vw - 32px)); }
#oauth-link-dialog h2 { margin: 0 0 12px; }
#oauth-link-dialog form { display: grid; gap: 10px; margin: 18px 0; }
#oauth-link-dialog input { box-sizing: border-box; width: 100%; min-height: 44px; }
#oauth-link-dialog .help { line-height: 1.5; }
/* One dialog padding for every popup — this and #oauth-link-dialog used to
   read 22px and 24px, two hand-set values for the same slot. */
.dialog-pad { padding: var(--pad-dialog); }
.dialog-pad h3 { margin-bottom: 8px; }
.dialog-pad p { color: var(--ink-muted); font-size: var(--type-lead); line-height: var(--type-lead-lh); margin: 0 0 16px; }
.dialog-actions { display: flex; justify-content: flex-end; gap: 8px; }
.dialog-actions .btn-primary { background: linear-gradient(135deg, var(--action-ink) 0%, color-mix(in srgb, var(--action-ink) 60%, var(--brand-bright)) 100%); border-color: var(--action-ink); color: var(--action-surface); box-shadow: 0 2px 12px rgb(var(--nota-blue-500-rgb) / .2), inset 0 1px 0 rgb(255 255 255 / .08); font-weight: 600; }
.dialog-actions .btn-primary:hover { background: linear-gradient(135deg, color-mix(in srgb, var(--action-ink) 80%, var(--action-accent)) 0%, color-mix(in srgb, var(--action-ink) 50%, var(--action-accent)) 100%); border-color: var(--action-accent); box-shadow: 0 4px 18px color-mix(in srgb, var(--action-accent) 30%, transparent), inset 0 1px 0 rgb(255 255 255 / .12); transform: translateY(-1px); }
/* The public rating badge — brand star, tabular figures, quiet count. */
.rating-badge { color: var(--brand); font-weight: 700; font-size: 12.5px; white-space: nowrap; font-variant-numeric: tabular-nums; }
.nc-own-rating { margin-bottom: var(--space-4); }

/* The CNQ membership pill and the official fiche link (ADR 0016). */
.cnq-badge {
  display: inline-block; padding: 0 6px; border: 1px solid var(--brand); border-radius: var(--radius-sm);
  color: var(--brand); background: var(--brand-tint-solid); font-weight: 700; font-size: 11px;
  line-height: 18px; white-space: nowrap; vertical-align: middle;
}
.cnq-link { font-size: 12.5px; white-space: nowrap; }
/* ADR 0030 — la pastille de cote et sa note d'explication ont été retirées des
   vues client : l'art. 70 du Code de déontologie interdit au notaire de
   permettre qu'un témoignage d'appui le concernant soit utilisé, et une note
   affichée transforme un annuaire en recommandation. Ce qui reste à côté du
   badge CNQ est un FAIT : le nombre d'actes portés sur Nota. */
.my-offer-acts { white-space: nowrap; }
#notary-profil .form-row { margin-bottom: var(--space-4); }
#nc-profil-form .btn { margin-top: var(--space-3); }

/* --- Notary evaluation (after the signed act, ADR 0015) ------------------- */
.my-offer-eval { margin-top: var(--space-6); padding: var(--pad-card); background: var(--surface-inset); border-radius: var(--radius); display: flex; flex-direction: column; gap: var(--space-4); }
.my-offer-eval-t { font-size: 13.5px; }
.eval-stars { display: flex; gap: 2px; }
.eval-star { appearance: none; border: 0; background: transparent; cursor: pointer; font-size: 24px; line-height: 1; padding: 2px 4px; color: var(--brand); }
.eval-star:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; border-radius: var(--radius-sm); }
.eval-comment { resize: vertical; }
.eval-submit { align-self: flex-start; }
.my-offer-eval-done { font-size: 13.5px; }
.my-offer-eval-done strong { color: var(--brand); }

/* Destructive confirm (cancel an offer): quiet red outline, filled on hover —
   visible enough to read as consequence, never louder than the safe way out. */
.btn-danger { color: var(--danger); border-color: var(--danger); }
.btn-danger:hover { background: transparent; border-color: var(--danger); color: var(--danger); box-shadow: inset 0 0 0 1px var(--danger); }
.btn-offer-cancel { color: var(--danger); }
/* Per-offer help door: a visible secondary action with a compact help mark.
   It stays at the end of the row on wide cards and becomes full-width on a
   narrow card, so it never reads like an unrelated browser-default button. */
.my-offer-help {
  margin-left: auto; align-self: center; display: inline-flex; align-items: center;
  gap: 7px; min-height: 34px; padding-inline: 12px; border-color: var(--brand);
  color: var(--brand-on-surface); font-weight: 700; white-space: nowrap;
}
.my-offer-help:hover { background: var(--action-tint); border-color: var(--action-ink); color: var(--action-ink); }
.my-offer-help-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 19px; height: 19px; border: 1.5px solid currentColor; border-radius: 50%;
  font-size: 13px; line-height: 1; font-weight: 800;
}
.my-offer-help:focus-visible { outline-offset: 3px; }
@media (max-width: 560px) {
  .my-offer-help { margin-left: 0; width: 100%; justify-content: center; }
}
/* The « ou écrivez-nous » quick line under the contact form's submit. */
#ct-quick { margin-top: 12px; text-align: center; }
#ct-quick:empty { display: none; }
/* --- « Nous joindre » (2026-09-04 redesign) ----------------------------------
   Scoped to the contact dialog — the shared dialog shell (.dlg-x-form,
   .dialog-actions, the 440px column) is untouched. The pass tightens every
   small space to the token scale, seats nom + courriel on one row where the
   column is wide enough, lets the message box grow with the text, and gives
   the sent state a real confirmation with its two actions. Under 480px the
   dialog becomes a full-width sheet with its own scroll, so a 320px phone
   never hides the Envoyer button below an unreachable fold. */
#contact-dialog .ct-pad { padding: var(--space-9) var(--space-9) var(--space-8); }
/* The sticky ✕ sits in the top-right corner: the title line and the lede's
   first line keep clear of it instead of running underneath. */
#contact-dialog h3 { margin-bottom: var(--space-3); padding-right: 52px; }
#contact-dialog .ct-lede { padding-right: 28px; }
#contact-dialog .ct-lede { font-size: 14px; line-height: 1.45; margin: 0 0 var(--space-6); max-width: 52ch; }
#contact-dialog .ct-trust {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-2);
  margin: calc(-1 * var(--space-2)) 0 var(--space-7); padding: var(--space-3);
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-inset);
}
#contact-dialog .ct-trust-item {
  display: flex; align-items: flex-start; gap: var(--space-2); min-width: 0;
  color: var(--ink); font-size: 11px; line-height: 1.25;
}
#contact-dialog .ct-trust-item strong,
#contact-dialog .ct-trust-item small { display: block; }
#contact-dialog .ct-trust-item strong { font-size: 11px; font-weight: 800; }
#contact-dialog .ct-trust-item small { margin-top: 2px; color: var(--ink-muted); font-size: 10.5px; line-height: 1.25; }
#contact-dialog .ct-trust-mark {
  display: inline-grid; place-items: center; flex: none; width: 20px; height: 20px;
  border-radius: 50%; background: var(--brand-tint); color: var(--brand); font-weight: 800;
}
#contact-dialog .form-row { margin-bottom: var(--space-5); }
#contact-dialog .lbl { margin-bottom: var(--space-2); }
#contact-dialog .ct-field-help { margin: var(--space-2) 0 0; font-size: 11.5px; line-height: 1.35; }
/* Le libellé et son compteur partagent UNE ligne — le compteur garde sa
   réserve (ADR 0039) sur une hauteur qui existait déjà. */
#contact-dialog .lbl-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); }
#contact-dialog .lbl-row .lbl { margin-bottom: var(--space-2); }
#contact-dialog .lbl-row .ct-count { margin: 0; }
#contact-dialog .lbl-hint { font-weight: 500; color: var(--ink-muted); }
#contact-dialog .ct-grid { display: grid; grid-template-columns: 1fr; gap: 0 var(--space-6); }
#contact-dialog textarea { min-height: 58px; max-height: 40vh; resize: vertical; }
#contact-dialog .ct-context { margin: calc(-1 * var(--space-3)) 0 var(--space-5); }

#contact-dialog #ct-quick { margin-top: var(--space-5); }
/* « Envoyer » suit le même registre que les autres formulaires (2026-09-07) :
   largeur de son libellé, jamais toute la feuille — et rangé à droite, là où
   .dialog-actions pose déjà les actions de tous les autres dialogues. */
#contact-dialog #ct-submit { display: flex; width: fit-content; min-width: 200px; margin-left: auto; }
/* The sent state: a check chip on the title line, one sentence, then the two
   actions — the messagerie first when the thread token came back. */
.ct-ok-head { display: flex; align-items: center; gap: var(--space-4); margin-bottom: var(--space-3); }
.ct-ok-ic { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; flex: none; border-radius: var(--radius); background: var(--brand-tint-solid-strong); color: var(--brand-on-tint-strong); }
.ct-ok-ic svg { width: 18px; height: 18px; }
#contact-dialog .ct-ok-title { margin: 0; font-size: 16px; color: var(--ink); }
#contact-dialog .ct-ok-body { margin: 0 0 var(--space-7); max-width: 46ch; }
.ct-ok-actions { flex-wrap: wrap; }
.ct-ok-actions .btn { flex: 1 1 auto; }
/* The dialog column is comfortable from 480px up; below, every side space
   shrinks one step and nom + courriel stack (a 300px column cannot hold two). */
@container (min-width: 380px) { #contact-dialog .ct-grid { grid-template-columns: 1fr 1fr; } }
#contact-dialog .dialog-pad { container-type: inline-size; }
@media (max-width: 479.98px) {
  #contact-dialog { width: calc(100vw - 16px); max-width: none; max-height: calc(100% - 16px); margin: 8px auto; }
  #contact-dialog .ct-pad { padding: var(--space-7) var(--space-6) var(--space-6); }
  #contact-dialog .ct-lede { margin-bottom: var(--space-5); padding-right: 52px; }
  #contact-dialog .ct-trust { grid-template-columns: 1fr; margin-bottom: var(--space-6); }
  #contact-dialog .form-row { margin-bottom: var(--space-5); }
  #contact-dialog textarea { min-height: 52px; }
}

/* --- Day detail dialog (enlarged day over a dimmed backdrop) -------------- */
/* La feuille suivait la fenêtre jusqu'à 620 px et s'arrêtait là, quelle que
   soit la taille de l'écran (2026-09-06) : sur un 27 pouces, les questions
   s'appariaient dans deux colonnes trop étroites, si bien qu'une réponse à
   trois boutons s'empilait en trois lignes à côté d'un simple champ. Elle
   grandit maintenant AVEC l'écran : 760 px reste le plancher de lecture et
   1 180 px le plafond, assez large pour que les choix et les champs forment
   des rangées nettes sans transformer la feuille en pleine largeur. */
#day-dialog { box-sizing: border-box; max-width: min(94vw, clamp(760px, 78vw, 1180px)); width: 94vw; max-height: min(90vh, 90dvh); overflow-y: auto; overscroll-behavior: contain; }
/* Sticky like the ✕ above it: the date being booked stays readable while the
   long booking form scrolls. padding-right clears the pinned ✕. */
.day-head { position: sticky; top: 0; z-index: 5; background: linear-gradient(to bottom, var(--surface-hover), var(--surface)); display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 8px 20px; padding: var(--space-8) 72px var(--space-5) var(--space-10); border-bottom: 1px solid color-mix(in srgb, var(--border-strong) 50%, var(--border)); }
.day-heading { min-width: 0; }
.day-eyebrow { margin-bottom: 4px; font-size: 12px; line-height: 1.4; color: var(--subtitle-ink); }
.day-title { margin: 0; }
.day-title::first-letter { text-transform: uppercase; }
.day-sub { font-size: 13px; color: var(--ink-muted); margin-top: 2px; }
/* The header's native date picker: the date moves without closing the dialog.
   Pushed to the right edge, inside the padding that clears the pinned ✕. */
.day-date-edit { min-width: 0; max-width: 100%; }
.day-date-edit > summary { display: flex; align-items: center; min-height: 44px; cursor: pointer; font-size: 13px; font-weight: 600; color: var(--brand-on-surface); text-decoration: underline; text-underline-offset: 3px; list-style: none; }
.day-date-edit > summary::-webkit-details-marker { display: none; }
.day-date-pick { display: flex; flex-direction: column; gap: 4px; min-width: 0; font-size: 12px; font-weight: 600; color: var(--ink-muted); }
.day-date-input { box-sizing: border-box; width: 100%; max-width: 220px; min-width: 0; min-height: 44px; font: inherit; font-size: 16px; padding: 8px 10px; border: 1px solid color-mix(in srgb, var(--border-strong) 70%, var(--border)); border-radius: var(--radius-sm); background: var(--surface-inset); color: var(--ink); }
.day-date-input:focus-visible { outline: 2px solid var(--action-ink); outline-offset: 1px; border-color: var(--action-ink); }
/* A tapped date opens a calm decision, with the market behind one disclosure.
   The same content stays readable in a phone sheet or on a touch desktop. */
#day-dialog[data-interaction='preview'] { width: min(94vw, 560px); max-width: 560px; }
#day-dialog[data-interaction='preview'] .day-head { grid-template-columns: minmax(0, 1fr); gap: 0; padding: 20px 68px 8px 20px; }
.day-preview { padding: 16px 20px max(20px, env(safe-area-inset-bottom)); }
.day-preview-intro { margin: 0 0 16px; color: var(--ink-muted); font-size: 14px; line-height: 1.5; }
#day-preview > button { width: 100%; min-height: 48px; justify-content: center; background: transparent; color: var(--action-ink); border-color: var(--action-ink); }
#day-preview > button:hover { background: var(--action-tint); color: var(--action-ink); border-color: var(--action-ink); }
.day-preview-offers { margin-top: 20px; border-top: 1px solid var(--border); }
.day-preview-offers > summary { display: flex; align-items: center; gap: 8px; min-height: 52px; cursor: pointer; color: var(--ink-muted); font-size: 13px; font-weight: 600; list-style: none; }
.day-preview-offers > summary::-webkit-details-marker { display: none; }
.day-preview-offers > summary::after { content: '+'; margin-left: auto; font-size: 20px; font-weight: 400; }
.day-preview-offers[open] > summary::after { content: '−'; }
.day-preview-count { min-width: 22px; padding: 2px 6px; text-align: center; background: var(--surface-inset); border-radius: var(--radius-xs); font-variant-numeric: tabular-nums; }
.day-preview-empty { margin: 16px 0 0; font-size: 12px; line-height: 1.5; color: var(--ink-muted); }
#day-preview .day-bids { max-height: none; overflow: visible; margin: 0; border-top: 0; }
#day-preview .bid-row { padding: 12px 0; display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 12px; border-left: 0; background: transparent; }
#day-preview .bid-meta { grid-column: 1; grid-row: 1 / 3; display: flex; flex-direction: column-reverse; min-width: 0; }
#day-preview .bid-sub { font-size: 13px; line-height: 1.4; font-weight: 600; color: var(--ink); overflow-wrap: anywhere; }
#day-preview .bid-who { font-size: 12px; font-weight: 400; color: var(--ink-muted); }
#day-preview .bid-amount { grid-column: 2; grid-row: 1; font-size: 15px; white-space: nowrap; }
#day-preview .bid-row > .pill { display: none; }
#day-preview .status-chip { grid-column: 2; grid-row: 2; max-width: 14ch; font-size: 11px; }
#day-preview .day-bids-count { display: none; }
@media (max-width: 680px) {
  #day-dialog .day-head { grid-template-columns: minmax(0, 1fr); gap: 0; padding: 16px 64px 8px 16px; }
  #day-dialog[data-interaction='preview'] { width: 100%; max-width: 100%; }
  .day-preview { padding-inline: 16px; }
}
@media (max-height: 480px) and (min-width: 681px) {
  #day-dialog[data-interaction='preview'] { max-height: 96dvh; }
  #day-dialog[data-interaction='preview'] .day-head { grid-template-columns: minmax(0, 1fr) auto; padding-block: 12px; }
  .day-preview { padding-top: 12px; }
  .day-preview-intro { margin-bottom: 12px; }
  .day-preview-offers { margin-top: 12px; }
}
/* What happens after a real publication (success screen) and, back from
   Checkout, the same line standing on « Mes offres ». */
.offer-success-next { margin-top: 6px; }
.checkout-notice { padding: 12px 16px; border: 1px solid var(--border); border-left: 3px solid var(--brand); border-radius: var(--radius-sm); font-size: 13px; line-height: 1.5; color: var(--ink); }

/* --- Day booking surface (acte → offre à battre → book, all in one dialog) - */
/* Act-scoped market context: the offer to beat FOR THE SELECTED ACT — one
   quiet strip inside step 1 (it changes with the chips), so step 3 keeps the
   only big number in the dialog. */
.day-market { background: var(--surface-inset); border-radius: var(--radius-sm); padding: 8px 12px; overflow: hidden; }
/* Centre-aligned, and the LABEL is the flexible column (it wraps within
   itself): the reference figure and the one-tap pill hold the right rail of
   the same row at every dialog width — the pill never strands on an orphan
   row with dead space beside it (owner, 2026-08-27: « align »). */
.day-market-line { display: flex; align-items: center; gap: 4px 10px; flex-wrap: wrap; min-height: 1.5em; }
/* No open offer for the act → the line is hidden outright (every date is
   bookable, so there is no bar to print); the hint below owns the message. */
/* 2026-09-05 : la capitale d'affichage criait (« CE QUE D'AUTRES OFFRENT CE
   JOUR-LÀ · REFINANCEMENT » sur deux lignes) alors que la carte porte déjà son
   titre. Le libellé redevient une légende : casse normale, poids moyen. */
.day-value-k { font-size: 12px; font-weight: 600; color: var(--ink-muted); flex: 1 1 12ch; min-width: 0; }
.day-value-v { font-size: 15px; font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; }
.day-value-note { min-height: 1.5em; font-size: 12px; color: var(--ink-muted); margin: 2px 0 0; }
/* The live line flips blue the moment the slider clears the bar. */
.day-value-note.is-ahead { color: var(--ok); font-weight: 600; }
/* One tap over the bar — small, inline, at the end of the strip's line. */
.day-beat {
  appearance: none; font: inherit; font-size: 12px; font-weight: 700; cursor: pointer;
  margin-left: auto; padding: 3px 10px; border-radius: var(--radius-sm);
  border: 1px solid var(--brand); background: transparent; color: var(--brand-on-surface);
  transition: background var(--motion-fast), color var(--motion-fast), border-color var(--motion-fast);
}
.day-beat:hover { background: var(--action-tint); border-color: var(--action-ink); color: var(--action-ink); }
/* Stepping back does not take its place with it: the label is written even
   while the button is off show, so the strip's line keeps its height and its
   wrap (ADR 0039 — une ligne tenue). */
/* The headline lands with a small settle; the amount echoes it after a one-tap
   jump. Both sit still under prefers-reduced-motion. */
@keyframes day-best-in { from { opacity: 0; transform: translateY(3px); } }
.day-value-v.pulse { animation: day-best-in var(--motion-ui) var(--ease-ui); }
.amount-big.flash { animation: day-best-in var(--motion-enter) var(--ease-ui); }
@media (prefers-reduced-motion: reduce) { .day-value-v.pulse, .amount-big.flash { animation: none; } }
/* Says what the calendar's % means, for the date being booked. Sits under the
   header — it depends on the DATE, not on the act chosen below. Top padding
   keeps it off the sticky header's border. */
.day-chance { margin: 0; font-size: 12px; line-height: 1.5; color: var(--ink-muted); }
.day-bids { max-height: 30vh; overflow: auto; overscroll-behavior: contain; border-top: 1px solid var(--border); }
/* Inside the market strip the list bleeds to the edges, so its border-top
   spans the strip and the rows keep their own gutters. */
.day-market .day-bids { margin: 8px -12px -8px; }
.day-bids:empty { display: none; }
.day-bids .bid-row:first-child { border-top: 0; }
.day-bids-rest[hidden] { display: none; }
/* The door to the rest of the day is INLINE on the totals line (owner,
   2026-08-27: « compacter ») — a quiet link-weight button holding the right
   rail of the count's own row, never a stacked full-width bar. */
.day-bids-toggle {
  appearance: none; border: 0; background: none; font: inherit; cursor: pointer;
  font-size: 12px; font-weight: 700; color: var(--brand);
  padding: 0; margin-left: auto; white-space: nowrap;
}
.day-bids-toggle:hover { text-decoration: underline; }
/* The day's totals under the single headline offer: how many for the act being
   booked, and how many that date carries in all — with the unfold door at the
   end of the same line. */
.day-bids-count { display: flex; align-items: center; gap: 4px 12px; flex-wrap: wrap; padding: var(--space-4) var(--space-12); font-size: 12px; color: var(--ink-muted); line-height: 1.5; }
/* Scale guard: a day-group caps its rows and links to the full day view. */
.day-book {
  padding: var(--space-7) var(--space-10) var(--space-10);
  border-top: 1px solid var(--border);
  background: var(--surface-inset);
  display: flex; flex-direction: column; gap: var(--space-6);
}
/* Each step is its own bordered card so the three-beat flow reads at a glance.
   Regular card padding — the dialog is a working surface, not a brochure
   (owner, 2026-08-27: « compacter toutes les sections »). */
.book-step { display: flex; flex-direction: column; gap: var(--space-4); padding: var(--pad-card); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
/* Step 3 — the offer — is the decision, so it is the dominant card. */
.book-step-offer { border-color: var(--border-strong); background: var(--surface-inset); }

/* --- La feuille de réservation en QUATRE ÉCRANS (ADR 0040) ---------------
   Retour du propriétaire (2026-09-05) : « l'expérience est vraiment confuse
   — le faire en plusieurs screens ». Les cinq blocs empilés donnaient une
   colonne à faire défiler où l'acte, les questions du notaire, le prix, le
   secteur et l'identité se disputaient le même premier regard.

   Un écran à la fois. La structure du formulaire NE CHANGE PAS : chaque bloc
   porte le numéro de l'écran auquel il appartient (`data-screen`), le
   formulaire porte celui où l'on est (`data-at`), et c'est le CSS seul qui
   n'en montre qu'un — un `display: none` retire déjà du parcours au clavier
   et de l'arbre d'accessibilité. */
.day-book > [data-screen] { display: none !important; }
.day-book[data-at='1'] > [data-screen='1'],
.day-book[data-at='2'] > [data-screen='2'],
.day-book[data-at='3'] > [data-screen='3'],
.day-book[data-at='4'] > [data-screen='4'] { display: block !important; }
@keyframes book-screen-enter {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}
.day-book[data-at] > [data-screen] {
  will-change: opacity, transform;
}
.day-book[data-at='1'] > [data-screen='1'],
.day-book[data-at='2'] > [data-screen='2'],
.day-book[data-at='3'] > [data-screen='3'],
.day-book[data-at='4'] > [data-screen='4'] {
  animation: book-screen-enter var(--motion-ui) var(--ease-ui) both;
}
/* BUG 2 — l'offre publiée : le rail et la barre d'action restaient à l'écran
   à côté de la carte de confirmation. « done » ne montre aucun écran, ni rail,
   ni barre. */
.day-book[data-at='done'] > .book-rail,
.day-book[data-at='done'] > .book-nav { display: none; }

/* Le rail : où l'on est, ce qui reste, et la porte de retour vers une étape
   déjà franchie. Une étape qu'on n'a pas encore atteinte n'est pas cliquable
   — on ne saute pas par-dessus une question du notaire. */
.book-rail { display: flex; align-items: stretch; gap: var(--space-2); list-style: none; margin: 0 0 var(--space-6); padding: 0; }
/* Le rail numérote les étapes ; la carte n'a pas à le refaire une ligne plus
   bas. Le libellé reste — il nomme l'écran — la pastille part. */
.day-book[data-at] .book-step > .book-step-lbl > .step { display: none; }
.book-rail li { flex: 1 1 auto; min-width: 0; }
.book-rail-b {
  appearance: none; width: 100%; height: 100%; display: flex; align-items: center; gap: 7px;
  padding: 7px 9px; font: inherit; font-size: 12px; font-weight: 650; text-align: left;
  color: var(--ink-muted); background: transparent; cursor: pointer;
  border: 0; border-top: 2px solid var(--border); border-radius: 0;
}
.book-rail-b::after {
  content: '';
  display: block;
  width: 0;
  height: 2px;
  margin-left: auto;
  background: var(--brand);
  transition: width var(--motion-enter) var(--ease-ui);
}
.book-rail li[data-state='done'] .book-rail-b::after,
.book-rail li[data-state='at'] .book-rail-b::after { width: 18px; }
.book-rail-b[disabled] { cursor: default; opacity: 0.55; }
.book-rail-n {
  flex: none; width: 19px; height: 19px; display: inline-flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 800; border-radius: var(--radius-xs);
  background: var(--surface-inset); color: var(--ink-muted);
}
.book-rail-t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.book-rail li[data-state='done'] .book-rail-b { color: var(--ink); border-top-color: var(--brand); }
.book-rail li[data-state='done'] .book-rail-n { background: transparent; color: var(--brand); border: 1.5px solid var(--brand); }
.book-rail li[data-state='at'] .book-rail-b { color: var(--ink); border-top-color: var(--brand); }
.book-rail li[data-state='at'] .book-rail-n { background: transparent; color: var(--brand); border: 1.5px solid var(--brand); }
/* Traversée sans y répondre : on peut y revenir, et le rail le dit. */
.book-rail li[data-state='open'] .book-rail-b { color: var(--ink); border-top-color: var(--warn); }
.book-rail li[data-state='open'] .book-rail-n { background: transparent; color: var(--warn); border: 1.5px solid var(--warn); }
.book-rail-b:focus-visible { outline: 2px solid var(--action-ink); outline-offset: 2px; }
/* Une étape sautée (l'acte n'a pas de questions) se dit à voix basse. */
.book-rail li[data-state='skip'] { display: none; }

/* Une seule barre d'action, toujours au même endroit, en bas : « Retour » à
   gauche, et à droite l'action qui fait avancer. Au dernier écran c'est
   « Publier mon offre » qui prend cette place — jamais deux boutons primaires
   à la fois. */
.book-nav { display: flex; align-items: center; gap: var(--space-4); margin-top: var(--space-2); }
.book-nav .book-back { flex: none; }
/* L'action va AU BOUT DE LA BARRE, elle ne la remplit pas (retour du
   propriétaire, 2026-09-07 : « button are too big, do not fill them ») :
   étirée sur toute la largeur restante, « Continuer » faisait un bandeau de
   600 px pour un mot, et le regard n'avait plus de point à viser. Elle garde
   une largeur de vraie cible et se range à droite, « Retour » à gauche. */
.book-nav .book-fwd, .book-nav #offer-submit { flex: 0 0 auto; width: auto; min-width: 200px; margin: 0 0 0 auto; }
.book-nav > [hidden] { display: none !important; }
/* La barre porte la SEULE décision de l'écran, et elle ne se lisait pas comme
   telle (propriétaire, 2026-09-06) : 37 px de haut sur 578 px de large, un
   trait vert sous le formulaire. Elle prend la hauteur d'une vraie cible —
   44 px à la souris AUSSI, pas seulement au doigt — et une ligne de texte plus
   grande. « Retour » monte à la même hauteur pour que la barre tienne d'un
   bord à l'autre, mais garde son encre sourde : deux poids, une seule action. */
.book-nav .book-fwd, .book-nav #offer-submit { min-height: 44px; font-size: 15px; }
.book-nav .book-back { min-height: 44px; }
/* Et elle rentre dans le rang : l'exception de l'aplat vert est LEVÉE
   (2026-09-07). Elle avait été posée le 2026-09-06 parce qu'un contour de
   44 px sur 560 se lisait comme un trait de séparation — c'était la LARGEUR le
   problème, pas le contour. Rendue à sa taille, l'action se lit comme partout
   ailleurs dans l'application : couleur de marque et graisse, jamais un aplat.
   Redit ici parce que l'id #offer-submit l'emporte sur la classe .btn-primary ;
   désactivé, il retombe sur les jetons d'inactif pour la même raison. */
.book-nav .book-fwd, .book-nav #offer-submit {
  background: transparent; border-color: var(--action-ink); color: var(--action-ink); font-weight: 700;
}
.book-nav .book-fwd:not(:disabled):hover, .book-nav #offer-submit:not(:disabled):hover {
  background: var(--action-tint); border-color: var(--action-ink);
}
.book-nav .book-fwd:disabled, .book-nav #offer-submit:disabled {
  background: transparent; border-color: var(--border); color: var(--ink-muted);
}
/* Le chevron dit le sens, et seulement où il est vrai : « Continuer » avance
   d'un écran, « Publier mon offre » conclut — celle-là n'en porte pas. */
.book-nav .book-fwd::after { content: '→'; font-size: 1.05em; line-height: 1; transition: transform var(--motion-fast) var(--ease-ui); }
.book-nav .book-fwd:not(:disabled):hover::after { transform: translateX(2px); }
@media (max-width: 480px) {
  /* Sur téléphone le rail garde les numéros et laisse tomber les mots : quatre
     libellés sur 375 px ne tiennent qu'en s'ellipsant tous. */
  .book-rail-t { display: none; }
  .book-rail-b { justify-content: center; padding-inline: 4px; }
}
@media (prefers-reduced-motion: reduce) {
  .day-book[data-at] > [data-screen] { animation: none; }
  .book-rail-b::after { transition: none; }
}
/* Pricing criteria woven into the booking flow (dossier merged with the process). */
.o-criteria { display: flex; flex-direction: column; gap: 10px; }
.crit-row { display: flex; flex-direction: column; gap: 6px; }
.crit-flag { display: flex; align-items: flex-start; gap: 9px; cursor: pointer; }
/* La case se pose SUR le rail des libellés : les marges par défaut du
   navigateur (4 px à gauche, 3 px à droite) la poussaient de quatre pixels
   vers l'intérieur, si bien qu'une question à cocher ne commençait pas où
   commencent les autres questions de la même carte. */
.crit-flag input { margin: 3px 0 0; flex: none; accent-color: var(--brand); }
.crit-text { display: flex; flex-direction: column; gap: 1px; }
.crit-label { font-size: 13.5px; font-weight: 600; color: var(--ink); }
/* The question's own line. Everything that used to print itself UNDER a
   question and grow the card — the awaited-answer mark, the situational
   notes — rides here instead, on a line the label already occupies. */
.crit-head { display: flex; align-items: baseline; flex-wrap: wrap; min-width: 0; }
/* Les réponses d'une question sont des BOUTONS, pas un affichage segmenté
   (retour du propriétaire, 2026-09-05 : « our button and form is hard to
   understand — keep it really straight forward »). Sur la piste commune, une
   option non choisie n'avait ni fond ni cadre : trois libellés posés sur une
   barre, dont on ne devinait ni qu'ils étaient cliquables ni lequel était pris.
   Ici chaque option porte son propre cadre, la piste s'efface, et la réponse
   retenue est peinte à la marque. */
.crit-row .seg { display: flex; flex-wrap: wrap; gap: var(--space-3); padding: 0; border: 0; background: none; }
/* Une réponse se dimensionne sur CE QU'ELLE DIT (retour du propriétaire,
   2026-09-07 : « button are too big »). Étirées sur la ligne entière
   (flex: 1 1 auto), « Non » et « Oui » devenaient deux pavés de 400 px pour
   trois lettres : la cible était énorme et le mot perdu au milieu, si bien que
   deux réponses opposées se lisaient comme deux bandeaux. Elles gardent un
   plancher — une cible reste une cible, même pour « Oui » — et s'arrêtent là
   où leur libellé s'arrête. La piste, elle, reste alignée à gauche : c'est une
   suite de choix, pas une barre à remplir. */
.crit-row .seg-btn {
  flex: 0 1 auto; min-width: 92px; max-width: 100%; text-align: center;
  padding: 6px 14px; border-color: var(--border); background: var(--surface); color: var(--ink);
}
.crit-row .seg-btn:hover { border-color: var(--border-strong); background: var(--action-tint); }
/* Sauf quand le rang PREND LA LIGNE ENTIÈRE (retour du propriétaire,
   2026-09-07 : « this is looking empty ») : trois réponses serrées contre le
   bord gauche d'une ligne de 900 px laissaient les deux tiers de la carte nus.
   Là, elles se répartissent sur la ligne — mais BORNÉES : au-delà d'environ un
   tiers de la ligne, un bouton redevient le pavé qu'on vient de retirer. Un
   rang qui PARTAGE sa ligne, lui, garde ses réponses à la taille du libellé :
   c'est la place disponible qui décide, jamais la question. */
.crit-row[data-large] .seg-btn { flex: 1 1 auto; max-width: 320px; }
/* À partir d'une grande feuille, une rangée explicitement large utilise
   l'espace disponible : deux choix opposés se lisent comme deux colonnes
   équilibrées, sans laisser un quart de carte vide après les libellés. Les
   rangées compactes gardent leur largeur naturelle. */
@media (min-width: 1100px) {
  .crit-row[data-large] .seg-btn { flex: 1 1 0; max-width: none; }
  /* On a wide sheet, a segmented answer is a question-wide decision. Keeping
     it in the two-column track leaves a conspicuous empty half-card whenever
     its neighbour has one more option. The controls share the full row and
     stay bounded to a comfortable reading width. */
  .crit-sec-grid > .crit-row:has(.seg) { grid-column: 1 / -1; }
  .crit-sec-grid > .crit-row:has(.seg) .seg-btn { flex: 1 1 0; max-width: 420px; min-height: 44px; font-size: 14px; }
  .dossier-pricing .crit-sec[data-groupe='pret'] .crit-row[data-crit='valeur_pret'] { grid-column: 1; grid-row: 1; }
  .dossier-pricing .crit-sec[data-groupe='pret'] .crit-row[data-crit='preteur'] { grid-column: 2; grid-row: 1; }
  .dossier-pricing .crit-sec[data-groupe='pret'] .crit-row[data-crit='contexte'] { grid-column: 1 / -1; grid-row: 2; }
  .dossier-pricing .crit-sec[data-groupe='pret'] .crit-row[data-crit='approbation_bancaire'] { grid-column: 1 / -1; grid-row: 3; }
  .crit-sec-t { font-size: 16px; }
  .crit-sec-aide { font-size: 13px; }
  .crit-label { font-size: 14px; }
}
/* La réponse retenue se RECONNAÎT, elle ne se REMPLIT pas (même retour : « do
   not fill them »). L'aplat de marque faisait de chaque réponse choisie une
   tuile verte pleine — six questions répondues et la carte n'était plus qu'une
   grille de blocs, où le prix « +400 $ » se lisait moins bien que le fond
   derrière lui. Ici : le cadre passe à la marque et double d'épaisseur (un
   `inset` plutôt qu'une bordure de 2 px, qui déplacerait le texte), l'encre
   suit, et une coche dit lequel est pris. Le registre du bouton primaire de
   l'application — couleur et graisse, jamais un aplat — vaut donc aussi pour
   les réponses.

   La coche a sa place RÉSERVÉE sur chaque option (registre ADR 0039) : elle
   n'apparaît pas, elle se dévoile — répondre, se raviser, répondre ailleurs ne
   fait jamais respirer la piste sous la main du client. */
.crit-row .seg-btn::before, .crit-row .seg-btn::after {
  content: '✓'; font-size: 11px; font-weight: 800; color: var(--brand); visibility: hidden;
}
.crit-row .seg-btn::before { margin-right: 6px; }
/* Le jumeau muet de la coche, à droite : la coche est posée AVANT le libellé,
   donc à elle seule elle décentrerait le mot de sept pixels sur une piste
   centrée. Il ne se montre jamais — il ne fait que rendre la boîte symétrique,
   à l'arrêt comme choisie. */
.crit-row .seg-btn::after { margin-left: 6px; }
.crit-row .seg-btn.is-on {
  background: var(--surface); border-color: var(--action-ink);
  box-shadow: inset 0 0 0 1px var(--action-ink);
  color: var(--action-ink); font-weight: 700;
}
.crit-row .seg-btn.is-on::before { visibility: visible; }
/* When the options cannot share one line (settleSegTracks measures), the
   track restacks as full-width rows — answer left, price right — instead of
   a ragged 2+1 wrap that reads as two controls. */
.crit-row .seg.seg-stack { flex-direction: column; align-items: stretch; }
.crit-row .seg-stack .seg-btn { display: flex; align-items: baseline; justify-content: flex-start; text-align: left; }
.crit-row .seg-stack .crit-add { margin-left: auto; padding-left: 12px; }
/* A required question still awaiting its answer carries a quiet amber dot —
   the same signal the hint line and the step tally speak. Direct child only:
   a companion field's own label must not double the mark. */
.crit-row.crit-missing > .crit-head > .crit-label::after {
  content: ''; display: inline-block; width: 6px; height: 6px; margin-left: 7px;
  border-radius: 50%; background: var(--warn); vertical-align: 1px;
}
/* One flash when the hint's door lands here, so the eye finds the line. */
@keyframes crit-attn {
  from { box-shadow: 0 0 0 4px color-mix(in srgb, var(--warn) 40%, transparent); }
  to { box-shadow: 0 0 0 4px transparent; }
}
.crit-row.crit-attn { animation: crit-attn 1.4s ease-out; border-radius: var(--radius-sm); }
@media (prefers-reduced-motion: reduce) { .crit-row.crit-attn { animation: none; } }
/* Déplacement: two compact segmented bars — where it signs, then the radius —
   each under the question it answers (audit §3.2), then the online opt-in
   line (§3.3) and the static caveats (§1.1) toggled by the direction. */
.crit-dep { display: flex; flex-direction: column; gap: 6px; align-items: stretch; }
.crit-dep-km[hidden], .crit-sublabel[hidden] { display: none; }
.crit-sublabel { font-size: 12.5px; font-weight: 600; color: var(--ink-muted); margin-top: 4px; }
.crit-urgence { margin-top: 4px; }
/* A default the client has not touched reads as a suggestion: the pressed
   answer keeps its place but drops the accent fill until it is confirmed. */
/* Un défaut que le client n'a pas touché reste une SUGGESTION : cadre en
   pointillé, pas de trait doublé, et pas de coche — la coche dit « vous avez
   répondu », ce qui serait faux tant qu'on n'y a pas touché. */
.crit-row[data-default='true'] .seg-btn.is-on { background: transparent; border-style: dashed; box-shadow: none; }
.crit-row[data-default='true'] .seg-btn.is-on::before { visibility: hidden; }
/* The awaited-answer note (audit 2.5), beside the dot, once the form is started. */
/* Its OWN line inside the head (the question columns are too narrow to carry
   the label and the message side by side), reserved from the first paint and
   emptied by visibility — so a question that is answered, then cleared, then
   answered again never moves the sheet under the client's hand. */
/* Elle se range CONTRE le libellé quand la colonne le permet, et ne bascule
   sur sa propre ligne que si elle n'y tient pas — l'aide étant passée derrière
   le « i », une ligne réservée par question obligatoire était devenue le
   principal gaspillage de hauteur de la carte (2026-09-05). Réservée dans les
   deux cas : visible ou non, elle occupe la même boîte. */
.crit-req { flex: 0 1 auto; margin-left: var(--space-5); font-size: 12px; font-weight: 600; color: var(--warn); }
.crit-req[data-on='false'] { visibility: hidden; }
.crit-row input[type='number'] { max-width: 180px; }
/* The bracket figure and its unit read as one control (like the offer box). */
.crit-unit-wrap { display: inline-flex; align-items: center; gap: 6px; }
.crit-unit { font-size: 13px; font-weight: 700; color: var(--ink-muted); }
/* Long option lists (the lender catalogue) render as a select (domain ui hint),
   enhanced into a Nota select — the width cap rides on the wrapper. */
.crit-row .nselect { max-width: 320px; }
/* The select's free-text companion (« Autre prêteur » → its name), revealed
   only while the opening option is chosen. */
/* Le compagnon d'une liste (« Autre prêteur » → son nom) occupe la place que
   l'aide vient de libérer : une ligne pour une ligne, donc répondre à la
   question ne déplace rien de ce qui suit. */
/* Le compagnon d'une liste (« Autre prêteur » → son nom) se range À CÔTÉ de la
   liste, sur la place que la grille laisse libre : l'aide étant passée derrière
   le « i », il n'y a plus de ligne à céder — et une réponse ne doit toujours pas
   pousser ce qui la suit (ADR 0039). */
.crit-row:has(> .crit-other) { flex-flow: row wrap; align-items: flex-start; column-gap: var(--space-8); }
.crit-row:has(> .crit-other) > .crit-head, .crit-row:has(> .crit-other) > .crit-effet { flex: 1 0 100%; }
.crit-row:has(> .crit-other) > .nselect, .crit-row:has(> .crit-other) > .help { flex: 0 1 300px; }
.crit-row:has(> .crit-other) > .crit-other { flex: 1 1 240px; }
.crit-other { display: flex; flex-direction: column; gap: 6px; margin-top: 0; }
.crit-other[hidden] { display: none; }
.crit-other input[type='text'] { max-width: 320px; }
/* Flat dollar effect of an answer, printed on the answer itself; inherits the
   chip's on-state colour so it stays readable on the accent background. */
.crit-add { margin-left: 6px; font-size: 11px; font-weight: 600; color: var(--ink-muted); font-variant-numeric: tabular-nums; }
.chip.is-on .crit-add, .seg-btn.is-on .crit-add { color: inherit; }
/* bookGoTo pose le focus sur le titre de l'écran (tabindex -1) pour que le
   clavier et le lecteur d'écran repartent du haut. Ce titre n'est PAS un
   contrôle : on ne l'atteint jamais en tabulant, et l'anneau de focus générique
   dessinait une boîte verte autour de « Les questions du notaire » qui se lisait
   comme une sélection restée coincée. Le focus reste posé — seule sa bague
   part. */
.book-step-lbl:focus-visible, .book-step-lbl:focus { outline: none; }
/* Même raison pour le dialogue lui-même : showModal() y pose le focus quand
   rien n'est autofocusable, et l'anneau générique cernait TOUTE la feuille d'un
   trait vert qu'on lisait comme une sélection coincée. */
dialog:focus, dialog:focus-visible { outline: none; }
/* Wrap allowed: on a phone the parenthetical drops to its own line instead of
   squeezing the title into a ragged two-column fold. */
.book-step-lbl { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; font-size: 14px; font-weight: 700; color: var(--ink); }
.book-opt { color: var(--ink-muted); font-weight: 600; font-size: 12px; }
/* Step 2's live tally — amber while answers are awaited, brand once complete. */
.crit-count { margin-left: auto; font-size: 11.5px; font-weight: 600; color: var(--warn); white-space: nowrap; font-variant-numeric: tabular-nums; }
.crit-count[data-state='done'] { color: var(--brand); }
/* L'écran 1 ne pose qu'UNE question, alors la réponse prend la place (ADR
   0040, 2026-09-05 : « il y a trop d'info, c'est trop petit »). Deux cartes
   à parts égales, assez hautes pour se viser du pouce, jamais trois par
   ligne : sous 360 px de large elles s'empilent plutôt que de rétrécir. */
#o-service-chips {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-auto-rows: 1fr;
  gap: var(--space-6);
  min-width: 0;
}
@media (max-width: 380px) { #o-service-chips { grid-template-columns: 1fr; } }
/* Booking chips are two lines — the act, then its own offre à battre for the
   date (no offer → no sub line: every act is always bookable, so only an
   amount is worth a line) — so the acts compare at a glance before one is
   chosen. */
#o-service-chips .chip {
  position: relative;
  width: 100%;
  min-width: 0;
  box-sizing: border-box;
  justify-content: center; flex-direction: column; align-items: center; gap: var(--space-3);
  padding: var(--space-8) var(--space-6); border-radius: var(--radius);
}
/* Le crochet du choix : il n'apparaît que sur la carte retenue, et il dit le
   choix sans dépendre de la couleur (le cadre et la teinte, eux, en dépendent). */
#o-service-chips .chip-svc-check {
  position: absolute; top: var(--space-4); right: var(--space-5);
  font-size: 13px; font-weight: 700; line-height: 1; color: var(--brand);
  opacity: 0; transform: scale(.7); transition: opacity var(--motion-fast) var(--ease-ui), transform var(--motion-fast) var(--ease-ui);
}
#o-service-chips .chip.is-on .chip-svc-check { opacity: 1; transform: none; }
/* La pastille du glyphe : la marque de l'acte, visée avant que le nom se lise.
   Elle porte l'état de la carte (survol, choix) — le cadre de la carte ne
   change alors que d'un cheveu, et le choix se voit quand même de loin. */
#o-service-chips .chip-svc-badge {
  width: 36px; height: 36px; flex: none; display: inline-grid; place-items: center;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-inset);
  transition: background var(--motion-fast), border-color var(--motion-fast);
}
#o-service-chips .chip:hover .chip-svc-badge { border-color: var(--action-ink); }
/* La carte retenue : la teinte, le cadre, le crochet et la pastille disent le
   choix — le NOM, lui, est un titre et reste à l'encre. */
#o-service-chips .chip.is-on { background: var(--action-tint); color: var(--ink); }
#o-service-chips .chip.is-on .chip-svc-badge { background: var(--surface); border-color: var(--action-ink); }
#o-service-chips .chip-svc-main { font-size: 15px; }
.chip-svc-main { display: inline-flex; align-items: center; gap: var(--space-3); font-size: 14.5px; font-weight: 700; }
.chip-svc-sub { font-size: 12px; font-weight: 700; color: var(--ink-muted); font-variant-numeric: tabular-nums; }
/* Réservée seulement si le jour porte un chiffre : les deux puces gardent la
   même hauteur quand on change d'acte, sans qu'un jour sans offre paie une
   ligne vide dans chaque carte. */
#o-service-chips[data-sub='true'] .chip-svc-sub { min-height: 1.45em; }
#o-service-chips .chip.is-on .chip-svc-sub { color: inherit; }
/* Le catalogue annoncé (D.ACTES_A_VENIR) : même carte, même hauteur, même
   place — mais un trait pointillé, une encre sourde et aucun état survolé,
   pour que l'œil aille d'abord aux deux actes qui, eux, se réservent. */
#o-service-chips .chip-soon {
  cursor: default; background: transparent; color: var(--ink-muted);
  border-style: dashed; border-color: var(--border); box-shadow: none;
}
/* Rien ne s'y survole ni ne s'y anime : une annonce n'est pas une cible. */
#o-service-chips .chip-soon:hover { background: transparent; border-color: var(--border); color: var(--ink-muted); transform: none; }
#o-service-chips .chip-soon .chip-svc-main { font-weight: 600; }
#o-service-chips .chip-soon .chip-svc-badge { background: transparent; border-style: dashed; }
/* Sur une feuille assez LARGE, les cartes d'acte se couchent : le glyphe à gauche, le
   nom à sa droite, le prix (ou « Bientôt ») au bout de la ligne. Debout, elles
   encaissaient toute la largeur gagnée en VIDE — près de 400 px de carte pour
   un mot, et deux actes seulement annoncés qui pesaient autant que les deux
   qui se réservent (capture du propriétaire, 2026-09-06).
   C'est la largeur de la FEUILLE qui décide, pas celle de l'écran : la feuille
   est un dialogue centré, sa largeur ne suit pas la fenêtre au même rythme.
   Là où le pouce vise — téléphone, feuille étroite — rien ne change : les
   cartes restent debout et hautes. */
.day-book { container-type: inline-size; container-name: book; }
@container book (min-width: 600px) {
  #o-service-chips .chip {
    flex-direction: row; justify-content: flex-start; align-items: center;
    gap: var(--space-6); padding: var(--space-6) var(--space-7); text-align: left;
  }
  /* Le montant du jour ferme la ligne, aligné d'une carte à l'autre. */
  #o-service-chips .chip-svc-main { min-width: 0; overflow-wrap: anywhere; }
  #o-service-chips .chip-svc-sub { margin-left: auto; padding-right: var(--space-6); flex: none; }
  /* Le crochet du choix reprend sa place au coin, dégagé du montant. */
  #o-service-chips .chip-svc-check { top: 50%; transform: translateY(-50%) scale(.7); }
    #o-service-chips .chip.is-on .chip-svc-check { transform: translateY(-50%); }
}
/* On narrow phones the four acts intentionally stay in one column, but they
   are still simple choices — not four tall poster cards. Keep the 44px touch
   floor while placing the icon, name and day figure on a compact two-line
   rail. One column also gives long names their full reading width. */
@media (max-width: 520px) {
  #o-service-chips { grid-template-columns: 1fr; grid-auto-rows: auto; gap: 8px; }
  #o-service-chips .chip {
    display: grid; grid-template-columns: 36px minmax(0, 1fr);
    grid-template-rows: auto auto; align-items: center; justify-content: stretch;
    gap: 2px 10px; min-height: 76px; box-sizing: border-box;
    padding: 10px 12px; text-align: left; white-space: normal;
  }
  #o-service-chips .chip-svc-badge { grid-column: 1; grid-row: 1 / span 2; }
  #o-service-chips .chip-svc-main {
    grid-column: 2; grid-row: 1; min-width: 0; font-size: 14px;
    line-height: 1.25; overflow-wrap: anywhere;
  }
  #o-service-chips .chip-svc-sub {
    grid-column: 2; grid-row: 2; min-height: 0 !important; margin: 0;
    padding: 0; line-height: 1.2;
  }
  #o-service-chips .chip-svc-check { top: 8px; right: 8px; font-size: 12px; }
}
#o-service-chips .chip-soon .svc-ic { opacity: .7; }
/* « Bientôt » tient sur la ligne RÉSERVÉE AU PRIX, sous le nom (2026-09-06) :
   sur la ligne du nom, la pastille poussait « Procuration » hors de l'axe de
   son glyphe, et la rangée annoncée se lisait de travers sous une rangée
   centrée. La carte garde la hauteur d'une carte réservable — la ligne
   existait déjà — et la mention se lit comme une note, pas un bouton. */
.chip-soon-tag {
  font-size: 9.5px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-muted); border: 1px solid var(--border);
  padding: 1px var(--space-3); border-radius: var(--radius-xs); white-space: nowrap;
}
.book-options { margin: 0; }
.book-options .form-row:last-of-type { margin-bottom: 0; }
/* The identity block of the booking sheet (ADR 0033): name, courriel,
   téléphone — set apart from the notary's questions by a rule, never folded.
   Les trois champs s'apparient sur la MÊME grille que les questions de
   l'écran 2 (2026-09-06) : trois champs à la file dans une feuille qui
   s'élargit devenaient trois barres de 700 px, et rien ne disait que le nom et
   le courriel vont ensemble. Même seuil que .crit-sec-grid, donc les deux
   écrans se replient au même endroit. */
/* TROIS colonnes tant que la feuille les porte (2026-09-07) : à deux, le
   téléphone fermait le bloc seul et traînait une demi-carte nue à sa droite —
   le dernier vide de l'écran 4. Les trois champs sont courts et se lisent d'une
   seule ligne ; `auto-fit` les replie à deux puis à un, sans palier écrit à la
   main. */
.book-identity {
  margin-top: var(--space-6); padding-top: var(--space-6); border-top: 1px solid var(--border);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-6) var(--space-9); align-items: start;
}
/* Le sélecteur d'écran impose `display: block !important` à chaque bloc de la
   feuille (.day-book > [data-screen]) : le bloc d'identité le redit au même
   poids, sur le même sélecteur porté d'une classe, sans quoi la grille
   ci-dessus n'est jamais appliquée. */
.day-book[data-at='4'] > .book-identity[data-screen='4'] { display: grid !important; }
@media (max-width: 560px) { .book-identity { grid-template-columns: minmax(0, 1fr); } }
.book-identity .form-row { margin: 0; }
.book-identity-signed-in {
  grid-column: 1 / -1; display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-6); padding: var(--space-5) var(--space-6);
  border: 1px solid var(--border-strong); border-left: 3px solid var(--brand);
  border-radius: var(--radius); background: var(--surface-inset);
}
.book-identity-signed-in[hidden] { display: none; }
.book-identity-signed-in-copy { min-width: 0; }
.book-identity-kicker {
  margin: 0 0 3px; color: var(--subtitle-ink); font-size: 11px; font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase;
}
.book-identity-title { margin: 0; line-height: 1.3; }
.book-identity-signed-in .help { margin: 5px 0 0; }
@media (max-width: 560px) {
  .book-identity-signed-in { align-items: flex-start; flex-direction: column; }
  .book-identity-signed-in .btn { width: 100%; }
}
/* Un champ se dimensionne sur ce qu'on y écrit : une barre de 700 px pour dix
   chiffres promet autre chose que ce qu'elle attend. */
@media (min-width: 561px) {
  .book-identity #o-telephone { max-width: 260px; }
}
/* Les trois lignes d'aide de l'écran 4 sont des PROMESSES (à qui va ce champ,
   ce qui reste privé) : elles se lisent, donc elles restent — mais serrées
   sous leur champ, jamais espacées comme un paragraphe. */
.book-identity .help { margin: var(--space-3) 0 0; }
/* « Où signez-vous ? » : trois caractères dans un champ court suivis d'un
   demi-écran nu, et l'explication qui prenait deux lignes pleines sous lui. Le
   champ et son explication se rangent CÔTE À CÔTE — la carte tient sur deux
   lignes au lieu de quatre. */
#prefix-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  align-items: center; gap: var(--space-3) var(--space-8);
}
#prefix-row > .lbl, #prefix-row > .prefix-preview { grid-column: 1 / -1; }
#prefix-row > #o-prefix { width: 96px; }
#prefix-row > .help { margin: 0; }
@media (max-width: 560px) { #prefix-row { grid-template-columns: minmax(0, 1fr); } }

/* Brand utility classes — replace ad-hoc inline styles, keep markup on-brand */
.w-full { width: 100%; }
.uppercase { text-transform: uppercase; }
.mb-xl { margin-bottom: 32px; }
.mt-sm { margin-top: 14px; }
.mt-md { margin-top: 0; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.actions-inline { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.offer-success { margin-top: 14px; padding: 12px 14px; background: var(--surface-inset); border-radius: var(--radius); border-left: 3px solid var(--ok); }
.offer-success-head { display: flex; align-items: flex-start; gap: 10px; }
.offer-success-logo { flex: none; display: block; }
.offer-success .mt-sm { margin-top: 0; }
.switch-title { font-weight: 600; font-size: 14px; }
.panel-narrow { max-width: 560px; margin: 18px 0 32px; }
/* Legal pages: the long-form list panel fills the width (its list is 2-column)
   so there is no blank right half. */
#pane-confidentialite .panel-narrow, #pane-conditions .panel-narrow, #pane-charte .panel-narrow { max-width: none; }
.h-sub { font-size: var(--type-h3); line-height: var(--type-h3-lh); letter-spacing: var(--type-h3-ls); margin-bottom: 12px; }

/* Participation and subscription share the same visual weight. */
.participation-options { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.participation-options .eyebrow { display: block; margin-bottom: 12px; }
.participation-options .card p { line-height: 1.6; }
.participation-lifecycle { margin-top: 24px; }
.participation-lifecycle p { max-width: 80ch; color: var(--ink-muted); font-size: 14px; line-height: 1.6; margin: 0 0 16px; }
.participation-lifecycle a { display: inline-flex; align-items: center; min-height: 44px; font-size: 14px; }
.participation-availability { margin: 20px 0 12px; }
@media (max-width: 700px) {
  .participation-options { grid-template-columns: minmax(0, 1fr); }
}

.notary-model-access { position: relative; z-index: 1; margin: 12px 0 0; line-height: 1.6; }
/* Cette ligne est de l'AIDE, pas une deuxième ligne de pitch. `.intro p`
   (0,1,1) battait `.help` (0,1,0) et la rendait à la taille du lede : en
   français elle tenait QUATRE lignes de corps — 102 px posés entre les boutons
   du héros et le calendrier, sur un téléphone (mesuré à 390 px, 2026-09-14).
   Elle reprend le registre de `.help` (styles.css:1851), celui que la ligne
   d'éligibilité de la porte Partenaires tient déjà à côté de son propre lede.
   Le lien reste cliquable en ligne : e2e/participation.spec.js le suit. */

/* --- Notary console ------------------------------------------------------ */
/* Two faces on one pane, toggled by whether the console (#notary-authed) is
   showing:
   • SIGNED-OUT → the Carnet's hero grammar (agenda providers = the action row,
     the month as the aside), then two veiled panels, then the account door.
   • SIGNED-IN → the working console alone, in a single wide column. */
#pane-notaires {
  --nc-offer-surface: color-mix(in srgb, var(--surface) 90%, var(--bg));
  --nc-offer-hover: var(--action-tint);
}
#pane-notaires > .wrap { display: flex; flex-direction: column; }
/* CONNECTÉ : la porte est un plan de travail, pas une vitrine. Toute la face
   publique se replie — la rangée des agendas et l'aparté du héros (le héros
   lui-même ne garde que son h1, hors écran, pour la navigation : voir plus
   bas), l'anatomie et la preuve, les deux voies, le bouton des obligations.
   `display: none` et non un simple masquage visuel : un lien d'agenda caché
   ne doit pas rester dans l'ordre de tabulation. La console porte ses propres
   boutons d'agenda (flux privé). */
#pane-notaires > .wrap:has(#notary-authed:not([hidden])) .hero-cta,
#pane-notaires > .wrap:has(#notary-authed:not([hidden])) #notary-requests,
#pane-notaires > .wrap:has(#notary-authed:not([hidden])) .calendar-subscription,
#pane-notaires > .wrap:has(#notary-authed:not([hidden])) .notary-carnet,
#pane-notaires > .wrap:has(#notary-authed:not([hidden])) .notary-request-preview,
#pane-notaires > .wrap:has(#notary-authed:not([hidden])) .intro--hero p,
#pane-notaires > .wrap:has(#notary-authed:not([hidden])) #notary-live,
#pane-notaires > .wrap:has(#notary-authed:not([hidden])) #notary-ai-voies,
#pane-notaires > .wrap:has(#notary-authed:not([hidden])) .nc-secondary { display: none; }
/* The landing's centrepiece: the live open inventory, directly under the one
   line of pitch. Cards mirror the console's .nc-card surface; the whole card
   is a button into the sign-in. */
.nc-live[hidden] { display: none; }
/* Les deux blocs sous le héros (« Ce que contient chaque demande », les deux
   voies) portent LE panneau voilé du carnet (#carnet-panel) : voile + flou,
   rayon des panneaux, aucun contour. Une seule règle pour les deux. */
.nc-live, .nc-voies {
  margin-top: var(--gap); padding: var(--space-9); border: 0; border-radius: var(--radius-lg);
  background: var(--surface-veil); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  box-shadow: var(--shadow);
}
.nc-live-head { display: flex; align-items: baseline; gap: var(--space-6); flex-wrap: wrap; margin-bottom: var(--space-5); }
.nc-live-h, .nc-live-sub { font-size: var(--type-h4); line-height: var(--type-h4-lh); letter-spacing: var(--type-h4-ls); margin: 0; color: var(--accent-blue); }
.nc-live-sub { margin: var(--space-12) 0 var(--space-5); }

/* --- La face publique de la porte (refonte du 2026-09-18) -------------------
   Héros : les actes de la ligne de pitch gardent l'encre du texte (un nom
   d'acte n'est pas un lien) ; la mention de synchronisation ferme l'aparté. */
.nc-lede-acte { color: var(--ink); font-weight: 600; white-space: nowrap; }
/* La rangée d'action du héros EST la rangée des agendas : elle garde le pas du
   héros (.hero-cta) plutôt que celui d'une carte (.sub-card-actions, qu'elle
   porte aussi pour la console et ses tests), et ses boutons gardent leur
   largeur naturelle. Au téléphone : quatre de front — ICS ne tombe jamais seul
   sur une rangée ; sous 360px, deux rangées de deux. */
#notary-providers { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-4); margin-top: 0; width: 100%; max-width: 47ch; }
/* L'action de la porte porte l'encre de SA section (guide : « Action primaire ·
   contour ») — le mauve des notaires, comme la tuile « +N autres demandes ». */
#notary-providers .btn { min-width: 0; min-height: 44px; gap: var(--space-3); padding-inline: var(--space-4); font-weight: 700; color: var(--action-ink); border-color: var(--action-ink); }
#notary-providers .btn:is(:hover, :focus-visible) { background: var(--action-tint); transform: translateY(calc(var(--space-1) * -1)); box-shadow: var(--shadow-sm); }
#notary-providers .btn:active { transform: none; box-shadow: none; }
@media (max-width: 520px) {
  #notary-providers { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-2); width: 100%; }
  /* 44px : la cible tactile (WCAG 2.5.5) — au doigt, c'est LE geste de la page. */
  #notary-providers .btn { min-width: 0; min-height: 44px; gap: var(--space-2); padding-inline: var(--space-1); font-weight: 600; letter-spacing: -.01em; }
  #notary-providers .brand-ic { width: var(--space-7); height: var(--space-7); }
}
@media (max-width: 359.98px) {
  #notary-providers { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.notary-carnet > .nc-sync-note { margin: var(--space-5) 0 0; max-width: 52ch; font-size: var(--type-eyebrow); line-height: var(--type-body-lh); }
.notary-request-preview { min-width: 0; }
.notary-request-preview > .help { margin: 0; font-size: var(--type-eyebrow); line-height: var(--type-body-lh); }
.notary-request-preview > .nc-live-tagline { margin-bottom: var(--space-4); }
.notary-request-preview > #notary-anatomy-more { margin-top: var(--space-4); }
/* Le second geste du héros, discret : lire les demandes avant de s'abonner. */
.nc-see-requests { margin-top: var(--space-4); }
/* LE RAIL DE SYNCHRONISATION (2026-09-20) — le carnet de Nota à gauche, l'agenda
   du notaire à droite, et entre les deux des demandes qui voyagent. C'est un
   DÉCOR (aria-hidden) : il montre que l'agenda RELIT le flux, il ne promet
   aucune cadence — la phrase sous le mois la dit. Mouvement d'ambiance : sa
   boucle se mesure en secondes et vit dans SON jeton, hors des trois barreaux
   (brand.html, « Ce qui ne suit pas le registre »). */
.nc-sync {
  --nc-sync-loop: 3.6s;
  display: grid; grid-template-columns: auto minmax(var(--space-16), 1fr) auto; align-items: center;
  gap: var(--space-6); margin-bottom: var(--space-8);
}
.nc-sync-end { display: inline-flex; align-items: center; gap: var(--space-3); min-width: 0; font-size: var(--type-eyebrow); font-weight: 700; letter-spacing: var(--type-eyebrow-ls); text-transform: uppercase; color: var(--ink); white-space: nowrap; }
.nc-sync-mark, .nc-sync-glyph { flex: none; width: var(--space-10); height: var(--space-10); }
.nc-sync-glyph { color: var(--action-ink); }
.nc-sync-end--agenda { animation: nc-sync-land var(--nc-sync-loop) var(--ease-ui) infinite; }
.nc-sync-track { position: relative; height: var(--space-3); overflow: hidden; }
.nc-sync-track::before { content: ''; position: absolute; inset-inline: 0; top: 50%; border-top: 2px dotted var(--border-strong); transform: translateY(-50%); }
/* Chaque paquet est une bande de la largeur du rail, son carré posé à gauche :
   translateX(100 %) le fait donc voyager d'un bout à l'autre, sans mesurer. */
.nc-sync-packet { position: absolute; inset: 0; opacity: 0; animation: nc-sync-travel var(--nc-sync-loop) var(--ease-ui) infinite; }
.nc-sync-packet::before { content: ''; position: absolute; left: 0; top: 0; width: var(--space-3); height: var(--space-3); border-radius: var(--radius-xs); background: var(--action-ink); }
.nc-sync-packet:nth-child(2) { animation-delay: calc(var(--nc-sync-loop) / 3); }
.nc-sync-packet:nth-child(3) { animation-delay: calc(var(--nc-sync-loop) * 2 / 3); }
@keyframes nc-sync-travel {
  0% { opacity: 0; transform: translateX(0); }
  12% { opacity: 1; }
  82% { opacity: 1; }
  100% { opacity: 0; transform: translateX(calc(100% - var(--space-3))); }
}
@keyframes nc-sync-land {
  0%, 88%, 100% { transform: none; }
  94% { transform: translateY(calc(var(--space-1) * -1)); }
}
/* Les demandes « atterrissent » dans le mois : le point de chaque jour ouvert
   arrive à son tour (--i posé par agenda-demo.js), sur le barreau des entrées. */
.nc-mobile-day.has-request::after { animation: nc-dot-land var(--motion-enter) var(--ease-ui) both; animation-delay: calc(var(--i, 0) * var(--menu-stagger)); }
@keyframes nc-dot-land { from { opacity: 0; transform: translateX(-50%) translateY(calc(var(--space-3) * -1)) scale(.4); } to { opacity: 1; transform: translateX(-50%); } }
/* La fiche du jour choisi se repose à chaque sélection (classe reposée par
   agenda-demo.js) : on voit QUE quelque chose a changé. */
.nc-mobile-offer.is-swapping > * { animation: fadeUp var(--motion-ui) var(--ease-ui) both; }
/* The real request continues below the introduction instead of waiting for
   the taller calendar. The live inventory then uses the full page width. */
@media (min-width: 1280px) {
  #pane-notaires .landing-hero { grid-template-rows: auto auto; }
  .notary-carnet { grid-column: 2; grid-row: 1 / span 2; }
  .notary-request-preview { grid-column: 1; grid-row: 2; }
}

/* L'anatomie d'UNE demande, dessinée comme l'événement d'agenda qu'elle sera :
   un filet de marque à gauche, le titre de l'événement, puis ses champs — cinq
   colonnes quand la place existe, deux au téléphone. */
.nc-anatomy {
  display: grid; gap: var(--space-6); padding: var(--space-8) var(--space-9);
  border: 1px solid var(--border); border-left: 3px solid var(--action-ink); border-radius: var(--radius);
  background: var(--surface-inset);
}
.nc-anatomy[hidden] { display: none; }
.nc-anatomy:empty { display: none; }
.nc-anatomy-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-5); }
/* « Exemple » : une étiquette au contour, jamais un aplat — elle dit que la
   fiche n'est PAS une demande du carnet. */
.nc-anatomy-example { padding: var(--space-1) var(--space-4); border: 1px solid var(--warn); border-radius: var(--radius-sm); font-size: var(--type-eyebrow); font-weight: 800; letter-spacing: var(--type-eyebrow-ls); text-transform: uppercase; color: var(--ink); }
.nc-anatomy-event { display: flex; align-items: center; gap: var(--space-4); min-width: 0; font-family: var(--font-display); font-size: var(--type-h3); line-height: var(--type-h3-lh); letter-spacing: var(--type-h3-ls); font-weight: var(--weight-display); color: var(--ink); overflow-wrap: anywhere; }
.nc-anatomy-glyph { flex: none; display: inline-flex; }
.nc-anatomy-rows { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--space-6) var(--space-8); margin: 0; padding-top: var(--space-6); border-top: 1px solid var(--border); }
.nc-anatomy-row { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.nc-anatomy-row dt { font-size: var(--type-eyebrow); font-weight: 700; color: var(--ink-muted); }
.nc-anatomy-row dd { margin: 0; font-size: var(--type-body); font-weight: 700; color: var(--ink); overflow-wrap: anywhere; }
.nc-anatomy-row[data-champ='montant'] dd { color: var(--brand-on-surface); font-variant-numeric: tabular-nums; }
.nc-anatomy-row .pill { align-self: flex-start; }
/* Le lien que porte l'événement d'agenda, MOT POUR MOT (apps/api/src/ics.js,
   DESCRIPTION du flux public). C'est un vrai bouton : il mène à la porte du
   compte, là où l'on retient — comme les tuiles du carnet plus bas. */
.nc-anatomy-link { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2) var(--space-5); padding-top: var(--space-6); border-top: 1px solid var(--border); }
.nc-anatomy-link-k { font-size: var(--type-eyebrow); font-weight: 700; color: var(--ink-muted); }
.nc-anatomy-link-btn { appearance: none; display: inline-flex; align-items: center; gap: var(--space-3); min-height: 44px; padding: 0; border: 0; background: none; font: inherit; font-weight: 700; text-align: left; color: var(--action-ink); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: var(--space-2); cursor: pointer; transition: color var(--motion-fast) var(--ease-ui), gap var(--motion-fast) var(--ease-ui); }
.nc-anatomy-link-btn:is(:hover, :focus-visible) { gap: var(--space-5); text-decoration-thickness: 2px; }
.nc-anatomy-link-btn:focus-visible { outline: 2px solid var(--ring); outline-offset: var(--space-1); border-radius: var(--radius-xs); }

/* LES DEUX VOIES (2026-09-20) — un comparatif, pas deux paragraphes : à gauche
   ce que le choix gouverne (et ce qu'il ne gouverne pas), puis deux tuiles
   ÉGALES, carrées, au contour. Aucune n'est « la bonne », aucune n'est un
   bouton : rien n'est en vente sur la page publique. Le prix est le seul bleu
   (registre d'encre : un montant mentionne, un titre reste à l'encre). */
.nc-voies { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-8); align-items: stretch; }
.nc-voies-intro { display: flex; flex-direction: column; gap: var(--space-5); min-width: 0; align-self: center; }
.nc-voies-title { margin: 0; font-family: var(--font-display); font-size: var(--type-h2); line-height: var(--type-h2-lh); letter-spacing: var(--type-h2-ls); font-weight: var(--weight-display); color: var(--ink); text-wrap: balance; }
.nc-voies-title em { font-style: normal; text-decoration: underline; text-decoration-color: var(--action-ink); text-decoration-thickness: 3px; text-underline-offset: var(--space-3); }
.nc-voies-lead, .nc-voies-pitch { margin: 0; max-width: 46ch; font-size: var(--type-body); line-height: var(--type-body-lh); color: var(--ink-muted); text-wrap: pretty; }
.nc-voies-lead { font-weight: 700; color: var(--ink); }
.nc-voie { --accent-line: var(--accent-blue); display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; padding: var(--pad-card-lg); border: 1px solid var(--border-strong); border-radius: var(--radius); background: var(--surface-inset); }
.nc-voie:nth-child(3) { --accent-line: var(--accent-purple); }
.nc-voie[hidden] { display: none; }
.nc-voie-k { font-family: var(--font-display); font-size: var(--type-h3); line-height: var(--type-h3-lh); letter-spacing: var(--type-h3-ls); font-weight: var(--weight-display); color: var(--ink); }
.nc-voie-price { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-3); margin-bottom: var(--space-2); font-family: var(--font-display); font-size: var(--type-h1-compact); line-height: var(--type-h1-lh); font-weight: var(--weight-display); font-variant-numeric: tabular-nums; color: var(--brand-on-surface); }
.nc-voie-price:empty { display: none; }
.nc-voie-per { font-family: var(--font-sans); font-size: var(--type-body); line-height: var(--type-body-lh); font-weight: 600; color: var(--ink-muted); }
.nc-voie-p { margin: 0; font-size: var(--type-body); line-height: var(--type-body-lh); color: var(--ink); text-wrap: pretty; }
.nc-voie-note { margin: auto 0 0; padding-top: var(--space-5); border-top: 1px solid var(--border); font-size: var(--type-eyebrow); line-height: var(--type-body-lh); color: var(--ink-muted); text-wrap: pretty; }
/* Sous le panneau : l'état (rien n'est en vente), l'objectif, puis les bornes. */
#notary-ai-voies { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: var(--space-8); align-items: start; }
#notary-ai-voies > .nc-voies { grid-column: 1 / -1; }
#notary-ai-voies > .help { grid-column: 1; margin: var(--space-5) 0 0; max-width: 88ch; }
#notary-ai-voies > .btn { grid-column: 2; grid-row: 2 / span 2; align-self: center; margin-top: var(--space-5); }
@media (max-width: 1099.98px) {
  .nc-voies { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .nc-voies-intro { grid-column: 1 / -1; }
}

/* Secondaire, en dernier : le bouton court vers les obligations. */
.nc-secondary { display: flex; flex-wrap: wrap; gap: var(--space-5); margin-top: var(--space-7); }
.nc-dialog { width: min(640px, calc(100vw - var(--space-16))); }
.nc-dialog .nc-conformite { margin-top: 0; padding-top: 0; border-top: 0; }

@media (max-width: 900px) {
  .nc-anatomy-rows { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 680px) {
  .nc-live, .nc-voies { padding: var(--space-7); }
  .nc-voies { grid-template-columns: minmax(0, 1fr); gap: var(--space-5); }
  #notary-ai-voies { grid-template-columns: minmax(0, 1fr); }
  #notary-ai-voies > .btn { grid-column: 1; grid-row: auto; justify-self: start; }
  .nc-anatomy { padding: var(--space-7); }
  .nc-anatomy-rows { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* La preuve tient sur UNE rangée : le nombre de colonnes est la constante
   NC_LIVE_ROW d'app.js, lue par --nc-live-row (4 par défaut, sans script). Les
   vraies cartes et les cases vides inertes partagent la même taille. Sous
   900px la rangée se plie en deux colonnes ; le téléphone a sa propre liste. */
.nc-live-grid { position: relative; display: grid; grid-template-columns: repeat(var(--nc-live-row, 4), minmax(0, 1fr)); grid-auto-rows: minmax(128px, 1fr); gap: var(--space-5); }
@media (max-width: 900px) {
  .nc-live-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.nc-live-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-width: 0; padding: var(--pad-card); text-align: center;
  color: var(--ink-muted);
}
.nc-live-empty { grid-column: 1 / -1; gap: var(--space-4); }
.nc-live-empty strong { color: var(--ink); font-size: 24px; letter-spacing: -0.02em; }
.nc-live-empty span { max-width: 28ch; font-size: 14px; }
/* The way out of an empty carnet. Deliberately not a card: a quiet band under
   the grid, so it reads as guidance and not as one more piece of inventory. */
.nc-live-next { display: flex; flex-direction: column; gap: var(--space-5); margin-top: var(--space-7); }
.nc-live-next-lede { max-width: 62ch; margin: 0; color: var(--ink-muted); font-size: 14px; line-height: 1.55; }
.nc-live-next-actions { display: flex; flex-wrap: wrap; gap: var(--space-5); }
/* The act's name never shares a line with the tier pill. It used to: at four
   up on a desktop the name had ~84px and read « Refinance… », at two up on a
   phone ~60px and read « Refin… » — refinancement and financement became the
   same card (owner, 2026-09-03). The act takes its own line, then the amount
   and its tier (the pairing a notary scans), then the date.

   container-type: the tile decides its own three- or four-line shape from ITS
   width, not from the viewport's — the same tile is 216px in a desktop rail of
   four and 175px two up on a phone, and it is the tile's width, never the
   screen's, that says whether « 9 410 $ » and « Prioritaire » fit on one line. */
.nc-live-card {
  container-type: inline-size;
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "svc svc" "amt pill" "meta meta";
  align-content: start; row-gap: 6px; column-gap: 8px; min-width: 0;
  padding: var(--pad-card); text-align: left; font: inherit; color: var(--ink);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--surface-inset); cursor: pointer;
  transition: transform var(--motion-fast), background-color var(--motion-fast), border-color var(--motion-fast), box-shadow var(--motion-fast);
}
.nc-live-card .nc-live-svc { grid-area: svc; }
.nc-live-card .pill { grid-area: pill; justify-self: end; align-self: center; }
.nc-live-card .nc-live-amt { grid-area: amt; }
.nc-live-card .nc-live-meta { grid-area: meta; }
/* A narrow tile: the widest amount (« 12 000 $ », 82px) plus the widest tier
   (« Prioritaire », 74px) plus the gap needs ~164px, so under 168px of tile
   CONTENT (what an inline-size container query measures — the padding is
   already out) the pill drops to its own line rather than landing on top of
   the money. Explicit line placement, which outranks the named areas above. */
@container (max-width: 168px) {
  .nc-live-card .nc-live-amt { grid-column: 1 / -1; }
  .nc-live-card .pill { grid-row: 3; grid-column: 1 / -1; justify-self: start; }
  .nc-live-card .nc-live-meta { grid-row: 4; grid-column: 1 / -1; }
}
.nc-live-card:hover { transform: translateY(-2px); background: var(--action-tint); border-color: var(--border-strong); box-shadow: var(--shadow); }
.nc-live-card:hover .nc-live-amt { color: var(--action-ink); }
.nc-live-card:active { transform: translateY(0); box-shadow: var(--shadow-sm); }
/* display: contents — the name and the pill become tiles of the card's own
   grid, each on the line it belongs to. The wrapper stays in the markup so
   ncLiveCard() keeps building one "top" row. */
.nc-live-top { display: contents; }
/* The span's colour is the act's --svc-* token (set inline) — it paints the
   glyph via currentColor; the act's NAME stays ink. Same grammar as the carnet. */
.nc-live-svc { display: flex; align-items: center; gap: 7px; min-width: 0; }
.nc-live-svc-name { font-size: 12.5px; font-weight: 700; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nc-live-amt { font-size: 19px; font-weight: 800; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; transition: color var(--motion-fast); }
.nc-live-meta { font-size: 12px; color: var(--ink-muted); }
/* Overflow card: "+N autres" — dashed, centred, with the notary accent.
   Hover and keyboard focus resolve the dashes into a solid accented door — the
   card reads as the entrance it is, not a disabled placeholder. */
.nc-live-more {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; text-align: center; gap: 4px;
  border-style: dashed; border-color: var(--border-strong); background: transparent; color: var(--action-ink);
}

/* Phones: a compact grid — eight single-column tiles pushed the sign-in a full
   screen down, so the tiles run two up and the funnel's gate stays in reach.
   auto-fit, not a hard two: at 320px two tiles cannot hold an amount and a
   tier side by side at all, so the grid falls to one full-width tile instead.
   AFTER the base rules — same specificity, so order is what decides. */
@media (max-width: 640px) {
  .nc-live-grid { grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr)); gap: var(--space-4); }
  .nc-live-card { padding: var(--space-5) var(--space-6); row-gap: 4px; }
  .nc-live-amt { font-size: 17px; }
  .nc-live-meta { font-size: 11px; }
}

.nc-live-more:is(:hover, :focus-visible) { border-style: solid; border-color: var(--action-ink); background: var(--action-tint); }
.nc-live-more strong { font-size: 14px; font-weight: 800; }
.nc-live-more .nc-live-meta { color: inherit; }

/* The hero's ONE pitch line, shown at every width. The old full paragraph and
   the numbered step list repeated what this line (and the guide) already
   say — one sentence carries the model, the CTAs carry the action. */
.hero-tagline strong { color: var(--ink); }

/* Week vignette — the marketplace played out with live data, in the onboarding
   dialog only. Real demands (D.weekAgenda) drop onto a Mon–Fri board one by one
   while the money counts up; the board then clears and replays the next batch.
   Borderless: the inset surface alone seats it. */
.nc-week[hidden] { display: none; }
.nc-week {
  /* ONE height for filled chips and empty ghost slots — a half-filled column
     must read as one grid, never as two misaligned ones. */
  --wk-cell-h: 46px;
  display: flex; flex-direction: column; gap: 12px;
  padding: var(--space-8) var(--space-9) 13px;
  border-radius: var(--radius);
  background: var(--surface-inset);
}
.nc-week-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.nc-week-kicker { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--subtitle-ink); }
.nc-week-total { position: relative; display: inline-flex; align-items: baseline; gap: var(--space-3); font-size: 13px; color: var(--ink-muted); }
.nc-week-total strong { display: inline-block; color: var(--brand); font-weight: 800; font-variant-numeric: tabular-nums; }
/* A small pop each time money lands on the board. */
.nc-week-total strong.is-tick { animation: nc-week-tick var(--motion-enter) var(--ease-ui); }
@keyframes nc-week-tick { 40% { transform: scale(1.12); } }
/* The landed amount floats up off the counter and dissolves. Its whole travel
   (top offset + peak translate) stays under the box's 16px top padding, so the
   float never escapes the vignette onto whatever sits above it. */
.nc-week-delta {
  position: absolute; right: 100%; margin-right: var(--space-4); top: -3px;
  font-size: 11px; font-weight: 800; color: var(--brand);
  white-space: nowrap; opacity: 0; pointer-events: none;
}
.nc-week-delta.is-live { animation: nc-week-delta .8s ease forwards; }
@keyframes nc-week-delta {
  0% { opacity: 0; transform: translateY(4px); }
  25% { opacity: 1; }
  100% { opacity: 0; transform: translateY(-10px); }
}
/* The board leaves with a little weight, not a flat fade. */
.nc-week-board { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 8px; transition: opacity var(--motion-enter) var(--ease-ui), transform var(--motion-enter) var(--ease-ui); }
.nc-week-board.is-out { opacity: 0; transform: translateY(6px) scale(.985); }
.nc-week-col { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.nc-week-day { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-muted); text-align: center; }
/* The day that just received a chip lights up for a beat. */
.nc-week-day.is-hit { animation: nc-week-day-hit .5s ease; }
@keyframes nc-week-day-hit { 30% { color: var(--brand); } }
/* Ghost slot: the empty half-hour a demand has not claimed (yet). */
.nc-week-slot { height: var(--wk-cell-h); border: 1px dashed var(--border); border-radius: var(--radius); }
/* A demand chip. `color` carries the act's --svc-* token (set inline) and the
   DOT says the service — the same visual grammar as the carnet's cells, where
   coloured borders belong to urgency, never to the act. */
.nc-week-chip {
  position: relative; height: var(--wk-cell-h); padding: 0 7px; min-width: 0;
  display: flex; flex-direction: column; justify-content: center; gap: 1px;
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  background: var(--surface);
  /* --tilt (set per chip by the builder) gives each drop its own slight lean,
     so eight landings read as eight objects instead of one stamped pattern. */
  opacity: 0; transform: translateY(-14px) scale(.88) rotate(var(--tilt, 0deg));
}
.nc-week-chip.is-in {
  opacity: 1; transform: none;
  transition: opacity var(--motion-ui) var(--ease-ui), transform var(--motion-enter) var(--ease-ui);
}
.nc-week-chip.is-in:hover { transform: translateY(-1px); box-shadow: var(--shadow); transition: transform var(--motion-fast) var(--ease-ui), box-shadow var(--motion-fast) var(--ease-ui); }
.nc-week-chip-top { display: flex; align-items: center; gap: 4px; min-width: 0; }
.nc-week-chip-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
/* 10px + tight tracking: a short act name fits a five-column dialog cell
   whole; longer ones ("Refinancement") ellipsize, with the glyph, colour and
   tooltip still naming them. */
.nc-week-chip-name { font-size: 10px; letter-spacing: -0.01em; font-weight: 600; color: var(--ink-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nc-week-chip-amt { font-size: 12.5px; font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; }
/* A taken demand flips once the board settles: the chip calms down and its ✓
   appears — the marketplace clearing, shown rather than claimed. */
.nc-week-chip-check {
  position: absolute; top: 3px; right: 6px;
  font-size: 10px; font-weight: 800; color: var(--brand);
  opacity: 0; transform: scale(.4);
}
.nc-week-chip.is-taken { opacity: .72; transition: opacity var(--motion-enter) var(--ease-ui); animation: nc-week-take var(--motion-enter) var(--ease-ui); }
@keyframes nc-week-take { 35% { transform: scale(.96); } }
.nc-week-chip.is-taken .nc-week-chip-check {
  opacity: 1; transform: none;
  transition: opacity var(--motion-enter) var(--ease-ui), transform var(--motion-enter) var(--ease-ui);
}
.nc-week-note { margin: 0; font-size: 11.5px; line-height: 1.5; color: var(--ink-muted); }
.nc-week-note[hidden] { display: none; }
.nc-week-check-key { color: var(--brand); font-weight: 800; }
@media (prefers-reduced-motion: reduce) {
  .nc-week-board { transition: none; transform: none; }
  .nc-week-chip, .nc-week-chip-check, .nc-week-chip.is-taken { opacity: 1; transform: none; transition: none; animation: none; }
  .nc-week-total strong.is-tick, .nc-week-delta.is-live, .nc-week-day.is-hit { animation: none; }
}

@media (prefers-reduced-motion: reduce) {
  .footer-social-link, .footer-contact-link { transition: none; }
  .footer-social-link:hover, .footer-contact-link:hover { transform: none; }
}
/* In the welcome dialog: sits under both views, left-aligned against the
   dialog's centred text. At dialog width the chip keeps the base two-line
   grammar — glyph + act name over the EXACT amount — so the board says what
   is sold and for how much without a hover. The vignette is a container so
   the chips re-lay by the DIALOG's width, not the viewport's. */
.nc-week--onb { margin-top: 18px; text-align: left; container: ncweek / inline-size; }
.nc-week--onb .nc-week-chip { overflow: hidden; }
/* Only a phone-narrow container trades words for the compact form: the name
   goes (the glyph + colour still say the act, the tooltip keeps the words),
   the amount swaps to the calendar's data-compact ("2,9k"), and the glyph
   stacks centred over it on a shorter cell — slots shrink with the chips
   through the shared --wk-cell-h, so the grid never splits in two. */
@container ncweek (max-width: 380px) {
  .nc-week--onb { --wk-cell-h: 38px; }
  .nc-week--onb .nc-week-board { gap: 5px; }
  .nc-week--onb .nc-week-chip { align-items: center; gap: 2px; padding: 0 4px; }
  .nc-week--onb .nc-week-chip-name { display: none; }
  .nc-week--onb .nc-week-chip-amt { font-size: 0; white-space: nowrap; }
  .nc-week--onb .nc-week-chip-amt::after { content: attr(data-compact); font-size: 10.5px; font-weight: 800; letter-spacing: -0.01em; }
}
/* Sur la page des notaires (propriétaire, 2026-09-12) : la même vignette, mais
   dans la carte d'abonnement, au-dessus des quatre boutons qu'elle explique.
   Container comme la variante du dialogue — la carte traverse toute la largeur
   au-delà de 1200px et se retrouve à 300px en dessous, donc les puces doivent
   se relire sur la CARTE, jamais sur la fenêtre. */
.nc-week--agenda { margin: var(--space-5) 0 var(--space-6); text-align: left; container: ncweek / inline-size; }
.nc-week--agenda .nc-week-chip { overflow: hidden; }
/* The narrow subscription rail keeps the total without a floating label
   crossing the calendar heading. The total itself still animates. */
.nc-week--agenda .nc-week-delta { display: none; }
@container ncweek (max-width: 380px) {
  .nc-week--agenda { --wk-cell-h: 38px; }
  .nc-week--agenda .nc-week-board { gap: 5px; }
  .nc-week--agenda .nc-week-chip { align-items: center; gap: 2px; padding: 0 4px; }
  .nc-week--agenda .nc-week-chip-name { display: none; }
  .nc-week--agenda .nc-week-chip-amt { font-size: 0; white-space: nowrap; }
  .nc-week--agenda .nc-week-chip-amt::after { content: attr(data-compact); font-size: 10.5px; font-weight: 800; letter-spacing: -0.01em; }
}

/* Notary flavour only: the same board also lands in their agenda. Decorative
   (it lives inside the aria-hidden vignette) — brand marks + one muted line. */
.nc-week-providers { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; font-size: 11.5px; line-height: 1.5; color: var(--ink-muted); }
.nc-week-providers[hidden] { display: none; }
.nc-week-providers .brand-ic { flex: none; }
/* The three agenda marks file in one after the other when the row appears. */
.nc-week-providers.is-live .brand-ic { animation: nc-prov-in var(--motion-enter) var(--ease-ui) backwards; }
.nc-week-providers.is-live .brand-ic:nth-of-type(2) { animation-delay: .12s; }
.nc-week-providers.is-live .brand-ic:nth-of-type(3) { animation-delay: .24s; }
@keyframes nc-prov-in { from { opacity: 0; transform: translateY(4px) scale(.8); } }

/* Bid vignette — the CLIENT onboarding step: ONE real demand played out end to
   end. The price climbs from the act's starting price to the offered amount,
   the demand is published au carnet, then a notaire retains it. Same inset
   surface as the week board; ob-bid-* names its own parts. */
.ob-bid[hidden] { display: none; }
.ob-bid {
  display: flex; flex-direction: column; gap: 12px;
  margin-top: 18px; padding: var(--space-8) var(--space-9) var(--space-7);
  border-radius: var(--radius);
  background:
    linear-gradient(to bottom, color-mix(in srgb, var(--surface-hover) 30%, transparent), transparent 50%),
    color-mix(in srgb, var(--surface) 85%, var(--bg));
  border: 1px solid color-mix(in srgb, var(--border-strong) 55%, var(--border));
  text-align: left;
}
/* One bid's story fades out as a block before the next one begins. */
.ob-bid-scene { display: flex; flex-direction: column; gap: 10px; transition: opacity var(--motion-enter) var(--ease-ui); }
.ob-bid-scene.is-out { opacity: 0; }
.ob-bid-card {
  display: flex; align-items: center; gap: 10px; min-width: 0;
  padding: 10px 12px;
  border: 1px solid color-mix(in srgb, var(--border-strong) 70%, var(--border)); border-radius: var(--radius);
  background: var(--surface);
  box-shadow: 0 2px 6px rgb(0 0 0 / .18);
}
/* Each bid's card settles in fresh… */
.ob-bid-scene.is-live .ob-bid-card { animation: ob-bid-card-in var(--motion-enter) var(--ease-ui) backwards; }
@keyframes ob-bid-card-in { from { opacity: 0; transform: translateY(8px) scale(.96); } }
/* …and rings once, the moment it lands au carnet. */
.ob-bid-card.is-pub { animation: ob-bid-pub .8s ease; }
@keyframes ob-bid-pub { 25% { border-color: var(--brand); box-shadow: 0 0 0 3px var(--ring); } }
/* `color` carries the act's --svc-* token (set inline); the glyph inherits it. */
.ob-bid-ic { flex: none; display: inline-flex; }
.ob-bid-main { flex: 1; display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.ob-bid-name { font-size: 12.5px; font-weight: 700; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ob-bid-date { font-size: 11px; color: var(--ink-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ob-bid-amt { flex: none; display: inline-block; font-size: 18px; font-weight: 800; color: var(--brand); font-variant-numeric: tabular-nums; }
.ob-bid-amt.is-tick { animation: nc-week-tick var(--motion-enter) var(--ease-ui); }
.ob-bid-stamps { display: flex; flex-direction: column; gap: 5px; }
/* Step stamps fade-and-rise in sequence: published, then retained/open. Each
   carries a dot that turns brand the moment its step is reached. */
/* flex-start + a nudged dot: when the stamp wraps to two lines on a narrow
   dialog, the dot stays with the FIRST line instead of floating between them. */
.ob-bid-stamp { display: flex; align-items: flex-start; gap: 7px; font-size: 11.5px; line-height: 1.5; color: var(--ink-muted); opacity: 0; transform: translateY(4px); }
.ob-bid-stamp::before { content: ''; flex: none; width: 5px; height: 5px; margin-top: 6px; border-radius: 50%; background: var(--border-strong); transition: background-color var(--motion-enter) var(--ease-ui); }
.ob-bid-stamp.is-on { opacity: 1; transform: none; transition: opacity var(--motion-enter) var(--ease-ui), transform var(--motion-enter) var(--ease-ui); }
.ob-bid-stamp.is-on::before { background: var(--action-ink); }
/* The closing stamp (retenue / ouverte) arrives with a touch more spring. */
#ob-bid-stamp-fin.is-on { animation: ob-bid-fin var(--motion-enter) var(--ease-ui); }
@keyframes ob-bid-fin { from { transform: translateY(6px) scale(.97); } }
@media (prefers-reduced-motion: reduce) {
  .ob-bid-scene { transition: none; }
  .ob-bid-scene.is-out { opacity: 1; }
  .ob-bid-stamp { opacity: 1; transform: none; transition: none; }
  .ob-bid-scene.is-live .ob-bid-card, .ob-bid-card.is-pub, #ob-bid-stamp-fin.is-on,
  .ob-bid-amt.is-tick, .nc-week-providers.is-live .brand-ic { animation: none; }
}

#notary-console { margin-top: 12px; max-width: none; }

/* Paid AI preparation is an optional work surface, not a gate on the free
   dossier. Keep its conversion card compact and let the normal checklist lead. */
.nc-ai-product {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 12px 20px;
  align-items: center; margin: 0 0 var(--space-6); padding: 16px 18px;
  border: 1px solid color-mix(in srgb, var(--brand) 28%, var(--border));
  border-radius: var(--radius); background: color-mix(in srgb, var(--brand-tint-solid) 42%, var(--surface));
}
.nc-ai-product-copy { min-width: 0; }
.nc-ai-kicker { margin: 0 0 3px; color: var(--subtitle-ink); font-size: 10px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; }
.nc-ai-title { margin: 0; color: var(--ink); font-size: var(--type-h3); line-height: var(--type-h3-lh); letter-spacing: var(--type-h3-ls); }
.nc-ai-lead { margin: 5px 0 0; color: var(--ink-muted); font-size: 13px; line-height: 1.45; }
.nc-ai-product-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 7px; }
.nc-ai-product-actions select, .nc-ai-product-actions input { min-height: 34px; max-width: 260px; padding: 6px 8px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--ink); font: inherit; font-size: 12px; }
.nc-ai-product-actions input { width: 60px; }
.nc-ai-quota { padding: 7px 10px; border-radius: var(--radius-sm); background: var(--surface); color: var(--brand-ink); font-size: 12px; font-weight: 750; }
.nc-ai-product-status { grid-column: 1 / -1; margin: 0; }
.nc-ai-questions { margin: 8px 0 16px; padding-left: 20px; }
.nc-ai-questions > li { margin: 0 0 14px; }
.nc-ai-question-feedback { margin-top: 8px; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-inset); }
.nc-ai-question-feedback .field { margin: 0 0 8px; }
.nc-ai-question-feedback textarea { width: 100%; min-height: 44px; resize: vertical; }
.nc-ai-question-feedback .btn { margin-top: 2px; }
.nc-ai-question-feedback [role='status'] { margin: 7px 0 0; }
@media (max-width: 680px) {
  .nc-ai-product { grid-template-columns: 1fr; }
  .nc-ai-product-actions { justify-content: flex-start; }
}
/* Gate headings (« Accédez aux demandes », « Vérifiez votre boîte courriel »)
   speak in the panel-heading register the partners form panel set: 18px,
   tightened, with the same breath below before the form begins. */
#notary-console .h-sub { margin-bottom: var(--space-8); }
/* Sign-in gate: ONE narrow column, shown as a solid card that anchors the right
   column of the landing (no bare floating field). The signed-in view keeps the
   same .panel .panel-pad card. */
.nc-gate { display: block; max-width: 440px; }
.nc-gate-main { min-width: 0; }
/* The gate's brand kicker — same grammar as the carnet card's « Votre outil
   de prospection », so the right column speaks with one voice. */
.nc-gate-kicker { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--accent-purple); margin-bottom: var(--space-3); }
/* On the brand-poured card the gate heading carries the column: a step up
   from the console's working 18px, still under the hero's h1. */
#notary-console .nc-gate .h-sub { font-size: var(--type-h2); line-height: var(--type-h2-lh); letter-spacing: var(--type-h2-ls); margin-bottom: var(--space-7); }
/* Panes move focus to their <h1> on navigation so screen readers announce the new
   page; that programmatic focus must NOT paint a ring on a non-interactive heading. */
.tab-pane h1:focus, .intro h1:focus { outline: none; box-shadow: none; }
/* Live echo of what the carnet will publish for this bid, colour-keyed to the
   state of the entry (valid Quebec sector / still typing / off-format). */
.prefix-preview { margin: 6px 0 0; min-height: 1.5em; font-size: 12px; line-height: 1.5; color: var(--ink-muted); }
.prefix-preview[data-state='ok'] { color: var(--brand); }
.prefix-preview[data-state='warn'] { color: var(--status-retenue); }
.nc-auth .form-row { margin-bottom: var(--space-7); }
/* The email field matches the button under it: at 120px it sat in the middle of
   an otherwise empty column. Field and CTA share one taller, 15px register —
   the pair must weigh as much as a demand card across the gap. */
.nc-auth .form-row input { width: 100%; padding: 10px 12px; font-size: 15px; }
/* Opaque surface under the brand outline: on the poured card a transparent
   button let the tint bleed through and the door dissolved into its wall. */
.nc-auth-cta { width: 100%; padding: 10px 16px; font-size: 15px; background: transparent; color: var(--brand-on-surface); border-color: var(--brand); }
.nc-auth-fine { margin-top: 10px; }
/* New-notary welcome: the gate's second step. It REPLACES the email step (the
   "Continuer" action branched here), so it must read as a welcome, not as an
   error bolted under a login form. The "Première visite" marker is the same
   outline pill as "Bientôt" — labelled, never alarming. */
.nc-signup { margin-top: 16px; max-width: 560px; padding: var(--pad-card-lg); display: flex; flex-direction: column; gap: 12px; border: 1px solid var(--brand); border-radius: var(--radius); background: var(--surface-inset); }
.nc-signup:focus { outline: none; }
.nc-signup-tag { margin: 0; align-self: flex-start; padding: 1px 9px; border: 1px solid var(--brand); border-radius: var(--radius-sm); font-size: 11px; font-weight: 800; letter-spacing: .03em; color: var(--brand); text-transform: uppercase; }
.nc-signup-back { align-self: flex-start; }
.nc-signup-lead { margin: 0; font-size: 14px; line-height: 1.5; color: var(--ink); }
.nc-signup-steps { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 6px; font-size: 13.5px; line-height: 1.45; color: var(--ink); }
/* No identity row in the console: the header account menu already says who is
   connected and carries Se déconnecter — the panel opens on the agenda. */
.nc-h { font-size: var(--type-h4); line-height: var(--type-h4-lh); letter-spacing: var(--type-h4-ls); margin: 18px 0 10px; }
.nc-list { display: flex; flex-direction: column; gap: 10px; }
/* Console lists are grids: a 1240px-wide strip per demand wastes the row and
   caps how many dossiers fit one screen. Open demands pack ~3-up; retained
   cards carry the client dossier and the completion form, so they get a wider
   2-up track. Cards stretch to equal row height, actions pinned to the foot. */
/* 320px track: two demands fit side by side from tablet width (768px) up —
   the more open bids on one screen, the stronger the pane's one message. */
.nc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr)); gap: 12px; }
.nc-grid--wide { grid-template-columns: repeat(auto-fill, minmax(min(480px, 100%), 1fr)); }

.nc-card {
  display: flex; flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface-inset); padding: var(--space-7);
  transition: transform var(--motion-fast), background-color var(--motion-fast), border-color var(--motion-fast), box-shadow var(--motion-fast);
}
.nc-card:hover { transform: translateY(-1px); background: var(--action-tint); border-color: var(--border-strong); box-shadow: var(--shadow-sm); }
.nc-card.is-retained { border-left: 3px solid var(--brand); }
.nc-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.nc-card-title { font-size: 15px; font-weight: 700; letter-spacing: -0.01em; }
.nc-card-amount { font-size: 19px; font-weight: 800; letter-spacing: -0.02em; white-space: nowrap; }
/* Signals row: tier / complexity / readiness — the only pills on the card.
   Everything descriptive (lender, perimeter, code) drops to the quiet facts
   line below, so the pills that remain actually mean "compare me". */
.nc-card-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 10px; }
.nc-date { font-size: 12px; color: var(--ink-muted); }
/* Case-complexity signal on a notary's open-bid card (outline, colour by level). */
.nc-complexity { font-size: 11px; font-weight: 700; padding: 1px 8px; border-radius: var(--radius-sm); border: 1px solid var(--border); color: var(--ink-muted); }
.nc-complexity[data-level='simple'] { color: var(--ok); border-color: var(--ok); }
.nc-complexity[data-level='complexe'] { color: var(--danger); border-color: var(--danger); }
/* The facts line: one muted sentence-row, dot-separated — reads as context,
   never competes with the signal pills. Children keep their classes (tests,
   urgence accent) but shed the pill chrome here. */
.nc-card-facts { margin-top: 7px; font-size: 12px; line-height: 1.6; color: var(--ink-muted); }
.nc-card-facts > * + *::before { content: '·'; margin: 0 7px 0 3px; color: var(--border-strong); font-weight: 400; }
.nc-card-facts .nc-lender, .nc-card-facts .nc-deplacement, .nc-card-facts .nc-prefixe, .nc-card-facts .nc-distance, .nc-card-facts .nc-date {
  display: inline-block; padding: 0; border: 0; background: none;
  font-size: 12px; font-weight: 600; color: var(--ink-muted); white-space: nowrap;
}
.nc-card-facts .nc-date { font-weight: 700; color: var(--ink); }
.nc-card-facts .nc-date::first-letter { text-transform: uppercase; }
.nc-card-facts .nc-lender-virt { margin-left: 5px; }
.nc-card-facts .nc-deplacement[data-urgence='true'] { font-weight: 700; }
/* The complexity answers, quoted under the facts: a hairline rule instead of
   a floating paragraph, so the block reads as "the file says…". */
.nc-factors {
  margin-top: 8px; padding: 2px 0 2px 10px;
  border-left: 2px solid var(--border-strong);
  font-size: 12px; line-height: 1.55; color: var(--ink-muted);
}
.nc-prefixe {
  font-size: 11px; font-weight: 700; color: var(--ink-muted);
  border: 1px dashed var(--border-strong); border-radius: var(--radius-sm); padding: 1px 6px;
}
.nc-ready {
  font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: var(--radius-sm); white-space: nowrap;
  background: var(--surface-inset); color: var(--ink-muted); border: 1px solid var(--border-strong);
}
.nc-ready[data-ready='true'] { color: var(--ok); border-color: var(--ok); }
/* Retenir owns the card FOOT — the quiet toolbar (.nc-card-more) sits just
   above it, so the primary confirm is the last thing the card says. The
   auto-margin that pins the foot rides the toolbar (it comes first in DOM)
   and only in the open agenda: retained cards keep flowing content. */
/* flex-wrap: the armed confirm (« Confirmer · N $ » + Annuler) widens the
   row — Détails wraps under instead of overflowing the card border. */
.nc-card-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding-top: 8px; }
/* Every offer uses the same natural height, across rows as well as within a
   row. Text can wrap or grow with a larger font without clipping information. */
#notary-open-list .nc-card { min-width: 0; padding: 14px; cursor: pointer; overflow-wrap: anywhere; }
#notary-open-list .nc-agenda-grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); align-items: stretch; grid-auto-rows: 1fr; }
#notary-open-list .nc-agenda-grid > .nc-card { align-self: stretch; }
#notary-open-list .nc-card-head { flex-wrap: wrap; gap: 4px 12px; }
#notary-open-list .nc-card-title { flex: 1 1 170px; }
#notary-open-list .nc-card-facts > * { max-width: 100%; white-space: normal; }
#notary-open-list .nc-card-meta > *, #notary-open-list .nc-status > * { white-space: normal; }
.nc-card-body { display: flex; flex-direction: column; gap: 2px; }
.nc-card-body[hidden] { display: none; }
.nc-card-location { display: flex; flex-wrap: wrap; gap: 4px 10px; color: var(--ink-muted); font-size: 13px; }
.nc-card-parameters { margin: 6px 0; color: var(--ink-muted); font-size: 13px; line-height: 1.5; }
.nc-card-parameters > div { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; padding-block: 5px; border-bottom: 1px solid var(--border); }
.nc-card-parameters dd { margin: 0; color: var(--ink); font-weight: 600; }
#notary-open-list .nc-card-body { border-top: 1px solid var(--border); padding-top: 10px; margin-top: 4px; }
#notary-open-list .nc-card-actions { margin-top: auto; }
.nc-card-actions .nc-toggle { margin-left: auto; color: var(--ink-muted); }
/* Retenir owns the card foot at every width — the confirm is the card's one
   job; Décliner tucks beside it as a small secondary. The cap keeps it a
   button, not a banner, when a card runs wide. */
.nc-card-actions .nc-accept { flex: 1 1 auto; max-width: 340px; }

/* --- Open agenda: one grid, the date on the card (ADR 0020) --------------- */
/* The date is an attribute of the demand, not a layout axis. A full-width
   band per day left the console 70 % empty whenever a day held one demand,
   and the lone card read as a bare price. Now the day strip sums the week in
   one slim row (each tile doubles as a day filter) and every card packs one
   responsive grid, chronological, saying its own signing day. */
.nc-open-tools {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px 14px; flex-wrap: wrap; margin: 0 0 14px;
}
.nc-filter { margin: 0; }
.nc-open-tools .nc-filter { flex: 1 0 100%; }
.nc-open-tools .nc-view-seg { margin-left: auto; }
.nc-filters-toggle { gap: 8px; min-height: 44px; }
.nc-filter-count { min-width: 20px; padding: 1px 5px; border-radius: var(--radius-xs); background: var(--brand-tint-solid); color: var(--brand-on-surface); }
.nc-filter-chevron { transition: transform var(--motion-fast); }
.nc-filters-toggle[aria-expanded='true'] .nc-filter-chevron { transform: rotate(180deg); }
.nc-days[hidden], .nc-filters-toggle[hidden], .nc-filter-count[hidden] { display: none; }
@media (max-width: 420px) {
  .nc-open-tools { gap: 8px; }
  .nc-open-tools .nc-view-seg { flex: 1 1 auto; }
  .nc-open-tools .nc-view-seg .seg-btn { flex: 1; padding-inline: 8px; }
}
.nc-filter[hidden] { display: none; }
.nc-view-seg[hidden] { display: none; }
.nc-filter .chip-svc-sub { margin-left: 2px; }
#notary-open-reset[hidden], .nc-offer-notice[hidden] { display: none; }
.nc-offer-notice { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; padding: 14px; margin-bottom: 16px; border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface); }
.nc-offer-notice p { flex: 1 1 260px; margin: 0; font-size: 14px; }
.nc-first-contact { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 12px 0; }
.nc-first-contact p { flex: 1 1 240px; margin: 0; font-size: 13px; color: var(--ink-muted); }
.nc-first-contact .btn { min-height: 44px; }
.nc-h .nc-h-amt { font-weight: 800; color: var(--brand); }
.nc-h .nc-h-sum { font-weight: 600; color: var(--ink-muted); }
.nc-agenda-list { display: flex; flex-direction: column; gap: 14px; }
/* The day rail: mini calendar cells — weekday over the day number, the day's
   money under it, the count as a corner badge. ONE scrollable row at every
   width (scroll-snap, thin scrollbar): a dozen wrapped tiles were a wall
   pushing the first demand below the fold. A pressed cell keeps only its day
   and the rest of the rail dims. */
.nc-days {
  display: flex; flex-wrap: nowrap; gap: 8px;
  overflow-x: auto; padding-bottom: 4px; scrollbar-width: thin;
  scroll-snap-type: x proximity;
}
.nc-daytile {
  /* Grow to share the full rail width (owner, 2026-08-27: no dead space at
     the end of the row); the 84px basis still overflows into scroll when a
     busy month packs more days than the row can hold. */
  position: relative; flex: 1 0 84px; scroll-snap-align: start;
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  min-width: 84px; padding: 8px 14px 9px; font: inherit; text-align: center; cursor: pointer;
  color: var(--ink); background: var(--surface-inset);
  border: 1px solid var(--border); border-radius: var(--radius);
  transition: background-color var(--motion-fast), border-color var(--motion-fast), box-shadow var(--motion-fast), opacity var(--motion-fast);
}
.nc-daytile:hover { background: var(--action-tint); border-color: var(--border-strong); }
.nc-daytile.is-on { border-color: var(--action-ink); box-shadow: inset 0 0 0 1px var(--action-ink); background: var(--action-tint); }
/* Holding a day mutes the rest of the rail — the choice reads at a glance. */
.nc-days.has-day .nc-daytile:not(.is-on) { opacity: .55; }
.nc-days.has-day .nc-daytile:not(.is-on):hover { opacity: 1; }
.nc-daytile-cal { display: flex; flex-direction: column; align-items: center; line-height: 1.1; }
.nc-daytile-wd { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .08em; color: var(--ink-muted); }
.nc-daytile-num { font-size: 19px; font-weight: 800; letter-spacing: -0.02em; }
.nc-daytile-mo { font-size: 10px; font-weight: 600; color: var(--ink-muted); }
/* "Today" earns the brand accent — it's the day a notary can still fill. */
.nc-daytile[data-today='true'] { border-color: var(--brand); }
.nc-daytile[data-today='true'] .nc-daytile-wd { color: var(--brand); }
.nc-daytile-sum { font-size: 12px; white-space: nowrap; }
.nc-daytile-sum.nc-day-total { font-weight: 800; color: var(--brand); }
/* The per-day count: a small square badge tucked in the cell's corner. */
.nc-day-badge {
  position: absolute; top: 4px; right: 4px; min-width: 16px; padding: 1px 4px;
  font-size: 10px; font-weight: 800; line-height: 1.3;
  color: var(--ink-muted); background: var(--surface-hover);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.nc-daytile.is-on .nc-day-badge { color: var(--action-ink); border-color: var(--action-ink); }
/* The card says its own day — a quiet kicker over the title; today keeps the
   brand accent so the fillable day pops out of the grid. */
.nc-card-when {
  display: flex; align-items: baseline; gap: 7px; margin-bottom: 6px;
  font-size: 11px; font-weight: 700; color: var(--ink-muted);
}
.nc-when-date::first-letter { text-transform: uppercase; }
.nc-when-rel { font-weight: 600; }
.nc-card-when[data-today='true'] .nc-when-rel { color: var(--brand); font-weight: 800; }

/* --- Card: status pills, secondary actions, inline forms ------------------ */
.nc-status { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.nc-pill {
  font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: var(--radius-sm); white-space: nowrap;
  background: var(--surface-inset); color: var(--ink-muted); border: 1px solid var(--border-strong);
}
/* The lender behind a demand — name + virtual (branchless) flag. The notary
   reads this before deciding; the roster in the préférences filters on it. */
.nc-lender {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: var(--radius-sm); white-space: nowrap;
  background: var(--surface-inset); color: var(--ink); border: 1px solid var(--border-strong);
}
.nc-lender-virt, .chip-lender-virt {
  font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .03em;
  padding: 0 6px; border-radius: var(--radius-sm); color: var(--warn, var(--ink-muted));
  border: 1px solid currentColor;
}
.chip-lender-virt { margin-left: 6px; }
/* Who travels for the in-person signature (ADR 0017). The 100 %-online urgency
   band is the outlier a notary opted into — it earns the warning accent. */
.nc-deplacement {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: var(--radius-sm); white-space: nowrap;
  background: var(--surface-inset); color: var(--ink); border: 1px solid var(--border-strong);
}
.nc-deplacement[data-urgence='true'] { color: var(--warn, var(--ink-muted)); border-color: currentColor; }
/* ADR 0035 — la garantie de paiement, sur la rangée de décision du notaire.
   Même registre que les autres signaux (même hauteur, même rayon) : ce n'est
   pas une alarme, c'est un fait à lire avant de retenir. Seul un refus ou une
   réservation expirée prend l'accent d'alerte — ce sont les deux seuls états
   qui appellent un geste. */
.nc-caution {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: var(--radius-sm); white-space: nowrap;
  background: var(--surface-inset); color: var(--ink-muted); border: 1px solid var(--border-strong);
}
.nc-caution[data-caution='posee'] { color: var(--ok); border-color: var(--ok); }
.nc-caution[data-caution='refusee'], .nc-caution[data-caution='expiree'] { color: var(--danger); border-color: var(--danger); }
.nc-caution-line { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 6px; }
.nc-caution-sub { font-size: 12px; color: var(--ink-muted); }
.nc-caution-row { margin-top: 6px; }
.nc-prop-pill[data-status='en_attente'] { color: var(--brand); border-color: var(--brand); }
.nc-prop-pill[data-status='acceptee'], .nc-docs-pill[data-fournie='true'], .nc-via-prop { color: var(--ok); border-color: var(--ok); }
.nc-prop-pill[data-status='refusee'] { color: var(--danger); border-color: var(--danger); }
/* Secondary actions read as a quiet toolbar — link-weight ghosts, no borders:
   three outlined buttons under an outlined primary was four boxes fighting.
   Hover restores the affordance. */
.nc-card-more { display: flex; flex-wrap: wrap; align-items: center; gap: 2px; margin-top: 10px; }
.nc-card-more .btn {
  border-color: transparent; background: transparent;
  color: var(--ink-muted); font-weight: 600; padding-inline: 9px;
}
.nc-card-more .btn:not(:disabled):hover { background: var(--action-tint); color: var(--ink); }
/* In the toolbar the agenda flows with its siblings — pushed right it dangled
   alone whenever the row wrapped. */
.nc-card-more .nc-agenda { margin-left: 0; }
.nc-card.is-declining { opacity: .75; }
.nc-undo-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: auto; padding-top: 12px; }
.nc-undo-lbl { font-size: 12px; font-weight: 700; color: var(--ink-muted); }

/* Agenda ▾ menu: a <details> that drops the three deeplinks under its button. */
.nc-agenda { position: relative; margin-left: auto; }
.nc-agenda > summary { list-style: none; cursor: pointer; }
.nc-agenda > summary::-webkit-details-marker { display: none; }
.nc-agenda > summary::after { content: ' ▾'; font-size: 10px; }
.nc-agenda-menu {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 3; min-width: 140px;
  display: flex; flex-direction: column; padding: 4px;
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--radius); box-shadow: var(--shadow);
}
.nc-agenda-item { display: flex; align-items: center; gap: 8px; padding: 7px 10px; font-size: 13px; font-weight: 600; color: var(--ink); text-decoration: none; border-radius: var(--radius-sm); }
.nc-agenda-item:hover { background: var(--action-tint); }

/* Inline forms (proposition / documents) open under the card's actions. */
.nc-inline { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 8px; }
.nc-form-h { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--subtitle-ink); }
.nc-form-row { display: flex; flex-wrap: wrap; align-items: end; gap: 8px; }
.nc-form-lbl { display: flex; flex-direction: column; gap: 4px; font-size: 12px; font-weight: 600; color: var(--ink-muted); }
.nc-propose-amt { max-width: 140px; }
.nc-propose-delta { font-size: 13px; font-weight: 800; color: var(--ok); padding-bottom: 8px; }
.nc-form-msg { width: 100%; resize: vertical; font: inherit; font-size: 13px; }
.nc-form-foot { display: flex; align-items: center; gap: 8px; }
.nc-form-errors { min-height: 1.5em; }
.nc-docs-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(220px, 100%), 1fr)); gap: 6px; }
.nc-docs-item { display: flex; align-items: center; gap: 8px; font-size: 13px; cursor: pointer; }
.nc-docs-name { flex: 1; min-width: 0; }
.nc-missing { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em; color: var(--danger); border: 1px solid var(--danger); border-radius: var(--radius-sm); padding: 0 6px; }

.nc-dossier { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
.nc-dossier-h { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--subtitle-ink); margin-bottom: 8px; }
.nc-workflow { margin: 12px 0 16px; padding: 12px 14px; background: var(--surface-inset); border: 1px solid var(--border); border-radius: var(--radius); }
.nc-workflow .nc-dossier-h { margin-bottom: 6px; }
.nc-workflow-ai { margin: 8px 0; font-size: 13px; color: var(--ink); }
.nc-workflow-actions { display: grid; gap: 7px; margin: 8px 0 0; padding-left: 22px; }
.nc-workflow-action { padding-left: 3px; color: var(--ink); }
.nc-workflow-action-meta { display: block; margin-top: 2px; font-size: 12px; color: var(--ink-muted); }
.nc-kv { display: grid; grid-template-columns: minmax(120px, 38%) 1fr; gap: 4px 12px; margin: 0; }
.nc-kv dt { font-size: 12px; font-weight: 600; color: var(--ink-muted); }
.nc-kv dd { font-size: 13px; color: var(--ink); margin: 0; overflow-wrap: anywhere; }
.nc-cal { margin-top: 18px; }
.nc-cal-h { font-size: 13px; font-weight: 700; margin-bottom: 8px; }
.nc-complete { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
.nc-complete-h { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-muted); margin-bottom: 8px; }
.nc-complete-row { display: flex; flex-wrap: wrap; align-items: end; gap: 8px; }
.nc-complete-amt { white-space: nowrap; }
.nc-complete-lbl { display: flex; flex-direction: column; gap: 4px; font-size: 12px; font-weight: 600; color: var(--ink-muted); }
.nc-actval { max-width: 140px; }
.nc-complete-done { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.nc-done-badge { font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: var(--radius-sm); white-space: nowrap; background: transparent; color: var(--ok); border: 1px solid var(--ok); }
.nc-done-fee { font-size: 12px; color: var(--ink-muted); }

/* Dossier post-publish bridge (in the day modal). */
.dossier-next { margin-top: 12px; padding: 12px 14px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); }
.dossier-next-row { display: flex; align-items: flex-start; gap: 10px; }
.dossier-next-txt { flex: 1; min-width: 0; }
.dossier-next-h { font-weight: 700; font-size: 14px; }
.dossier-next-badge { flex: none; font-size: 12px; font-weight: 800; padding: 2px 9px; border-radius: var(--radius-sm); background: var(--surface-inset); color: var(--ink); }
.dossier-next .dossier-bar { margin: 10px 0 0; }

/* Notaires: onboarding form + console side by side (use the horizontal space). */
/* Single full-width notary console (the page's one tool) + get-paid step. */
.nota-guarantee { margin-top: var(--gap); }
/* Lead-delivery preferences — how (in-app/email/SMS) + pace + which acts. */
/* Alert preferences — settings, not the working surface: a collapsed panel
   below the money. The summary row is the whole control; a chevron flips open. */
.nc-prefs { margin: 18px 0 8px; padding: var(--space-6) var(--space-9); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-inset); }
.nc-prefs[open] { padding-bottom: 16px; }
.nc-prefs-sum { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; cursor: pointer; list-style: none; }
.nc-prefs-sum::-webkit-details-marker { display: none; }
.nc-prefs-sum::after { content: '▾'; margin-left: auto; color: var(--ink-muted); font-size: 12px; transition: transform var(--motion-fast); }
.nc-prefs[open] .nc-prefs-sum::after { transform: rotate(180deg); }
.nc-prefs-sum .nc-h { margin: 0; }
.nc-prefs-hint { font-size: 12px; color: var(--ink-muted); }
.nc-prefs > .help { margin-top: 10px; }
/* « Vos évaluations » (ADR 0021): the notary's track record inside the same
   collapsed register. Each evaluation carries the facteurs' hairline left
   rule — the client's words, quoted in quiet type under the stars. */
.nc-evals { margin-top: 10px; }
.nc-zero-count, .nc-svc-count, .chat-doc-count { color: var(--ink-muted); font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; }
.nc-zero-count { margin: 8px 0; }
.nc-svc-count { margin: 2px 0 8px; }
.nc-evals-own { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; margin-bottom: var(--space-4); }
.nc-eval { margin-top: 10px; padding: 2px 0 2px 10px; border-left: 2px solid var(--border-strong); }
.nc-eval-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.nc-eval-stars { color: var(--brand); font-weight: 700; letter-spacing: 2px; white-space: nowrap; }
.nc-eval-svc { font-size: 13px; font-weight: 600; }
.nc-eval-date { font-size: 12px; color: var(--ink-muted); }
.nc-eval-date::first-letter { text-transform: uppercase; }
.nc-eval-comment { margin: 4px 0 0; font-size: 13px; line-height: 1.55; color: var(--ink-muted); }
.nc-prefs-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr)); gap: 8px 36px; margin-top: 8px; align-items: start; }
.nc-pref-block { min-width: 0; }
.nc-pref-title { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-muted); margin-bottom: 4px; }
.nc-pref-lbl { font-size: 13.5px; }
.nc-pref-pace { display: inline-flex; flex-wrap: wrap; margin: 2px 0 6px; max-width: 100%; }
.nc-pref-pace .seg-btn { font-size: 12.5px; }
/* The line is held whether or not the confirmation is on it — a note that
   appears for two seconds must not shove the preferences under it. */
.nc-prefs-saved { min-height: 1.5em; color: var(--ok); font-weight: 700; margin-top: 10px; }
.nc-pref-lenders { margin-top: 4px; }
/* The full lender roster reads better on its own row of the prefs grid. */
.nc-pref-block--wide { grid-column: 1 / -1; }

/* --- Retained-act conversation (client ↔ notaire) ------------------------ */
/* One construction for both sides: thread of bubbles (mine right, theirs
   left), then a write row. Tokens only — the theme swaps for free. */
.chat { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border); }
.chat-thread { display: flex; flex-direction: column; gap: 6px; max-height: 260px; overflow-y: auto; }
.chat-empty { font-size: 12.5px; color: var(--ink-muted); margin: 0; }
.chat-msg { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
.chat-msg.is-mine { align-items: flex-end; }
.chat-bubble {
  max-width: 85%; padding: 7px 11px; font-size: 13.5px; line-height: 1.45;
  background: var(--surface-inset); color: var(--ink);
  border: 1px solid var(--border); border-radius: var(--radius-lg) var(--radius-lg) var(--radius-lg) var(--radius-xs);
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.chat-msg.is-mine .chat-bubble {
  background: color-mix(in srgb, var(--brand) 12%, var(--surface));
  border-color: color-mix(in srgb, var(--brand) 35%, var(--border));
  border-radius: var(--radius-lg) var(--radius-lg) var(--radius-xs) var(--radius-lg);
}
.chat-when { font-size: 10.5px; color: var(--ink-muted); }
/* « Vu » (2026-09-04): the other side's read receipt, one quiet word under the
   last own message they have read — the same register as the time stamp. */
.chat-msg .chat-seen { display: block; font-size: 11px; color: var(--ink-muted); margin-top: 2px; }
.chat-msg.is-mine .chat-seen { text-align: right; }
.chat-row { display: flex; align-items: flex-end; gap: 8px; }
.chat-input { flex: 1 1 auto; resize: vertical; min-height: 40px; }
/* The shared composer (chatComposer): the write row, then a meta line — the
   refusal on the left, the « N / 500 » counter on the right from 400 on. */
.chat-write { display: flex; flex-direction: column; gap: 4px; }
.chat-composer .chat-input { resize: none; overflow-y: auto; max-height: 160px; }
.chat-meta { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); min-height: 0; }
.chat-error { margin: 0; font-size: 12.5px; color: var(--danger); }
.chat-count { margin-left: auto; font-size: 11px; color: var(--ink-muted); font-variant-numeric: tabular-nums; }
.chat-error, .chat-count { min-height: 1.5em; }
.nc-chat .nc-dossier-h, .my-offer-chat-h { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-muted); }

/* --- Withdrawal (désistement) after acceptance --------------------------- */
.nc-release { margin-top: 10px; padding-top: 8px; border-top: 1px dashed var(--border); }
.nc-release-open { font-size: 12.5px; color: var(--ink-muted); }
.nc-release-form { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.nc-release-motif { resize: vertical; min-height: 40px; }
.nc-release-actions { display: flex; align-items: center; gap: 8px; }
.nc-release-terms { margin: 0; }

/* --- La mise en relation est complète (ADR 0033) ------------------------- */
/* The contact gate, said over the working surface: a brand-tinted band
   naming the missing fields, one door into the form. Square register. */
.nc-banner {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;
  gap: var(--space-6) var(--space-9); margin: 0 0 var(--space-7);
  padding: var(--space-6) var(--space-8);
  border: 1px solid var(--brand); border-radius: var(--radius); background: var(--brand-tint-solid);
}
.nc-banner[hidden] { display: none; }
.nc-banner-body { flex: 1 1 280px; min-width: 0; }
.nc-banner-h { font-size: 14px; font-weight: 800; letter-spacing: -0.01em; color: var(--subtitle-ink); }
.nc-banner-p { margin: var(--space-2) 0 0; font-size: 13px; color: var(--ink-muted); }
.nc-banner-list { margin: var(--space-2) 0 0; padding-left: 18px; font-size: 13px; color: var(--ink); }
.nc-banner-list li { padding: 1px 0; }
/* The identity fields (nom / étude / téléphone / adresse) sit two-up. */
.nc-profil-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); gap: 0 var(--space-8); }
.nc-field-err { min-height: 1.5em; color: var(--danger); }
/* « Votre client » leads the retained card: the name, the two contact links
   (the phone glyph rides the tel:), then the facts that frame the signing. */
.nc-client { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
.nc-client-nom { font-size: 15px; font-weight: 700; letter-spacing: -0.01em; }
.nc-client-links { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-8); margin-top: var(--space-2); }
.nc-client-tel, .nc-client-mail {
  display: inline-flex; align-items: center; gap: 6px; min-height: 28px;
  font-size: 13px; font-weight: 600; color: var(--brand); text-decoration: none; overflow-wrap: anywhere;
}
.nc-client-tel:hover, .nc-client-mail:hover { text-decoration: underline; }
.nc-client-facts { margin-top: var(--space-3); }
/* Retained files: a compact overview, then one full-width working surface.
   auto-fit releases empty tracks when there is only one retained file. */
#notary-retained-list {
  grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr));
  grid-auto-rows: auto;
  align-items: stretch;
}
#notary-retained-list:has(> .is-expanded) { grid-template-columns: minmax(0, 1fr); }
#notary-retained-list .nc-card { min-width: 0; container-type: inline-size; }
#notary-retained-list .nc-card.is-expanded { grid-column: 1 / -1; }
#notary-retained-list .nc-card:hover { transform: none; }
.nc-retained-summary, .nc-retained-overview, .nc-retained-file { min-width: 0; }
.nc-retained-summary .nc-card-head { flex-wrap: wrap; }
.nc-retained-summary .nc-card-title { flex: 1 1 170px; overflow-wrap: anywhere; }
.nc-retained-summary .nc-client-links > * { min-width: 0; overflow-wrap: anywhere; }
.nc-retained-summary .nc-client-links svg { flex: 0 0 auto; }
.nc-retained-summary .nc-card-facts > * { max-width: 100%; white-space: normal; overflow-wrap: anywhere; }
.nc-retained-actions { margin-top: auto; padding-bottom: 0; }
.nc-retained-buttons { display: flex; flex-wrap: wrap; gap: 8px; width: 100%; }
.nc-retained-buttons > .btn { flex: 1 1 150px; }
.nc-retained-workspace {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px;
  margin-top: 20px; padding-top: 20px; border-top: 1px solid var(--border);
}
.nc-retained-workspace[hidden] { display: none; }
.nc-retained-workspace > .nc-chat, .nc-retained-file > .nc-dossier { margin-top: 0; padding-top: 0; border-top: 0; min-width: 0; }
.nc-retained-workspace .chat-bubble, .nc-retained-workspace .nc-kv dd { overflow-wrap: anywhere; }
.nc-retained-workspace .chat-row { flex-wrap: wrap; }
.nc-retained-workspace .chat-input { min-width: 0; flex-basis: 180px; }
.nc-retained-workspace .nc-card-more { flex-wrap: wrap; }
.nc-retained-workspace .nc-release-open { white-space: normal; text-align: left; min-height: 44px; }
@container (min-width: 720px) {
  .nc-retained-summary { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 24px; }
  .nc-retained-summary .nc-client { margin: 0; padding: 0 0 0 24px; border-top: 0; border-left: 1px solid var(--border); }
  .nc-retained-actions { justify-content: space-between; padding-top: 20px; }
  .nc-retained-buttons { width: auto; }
  .nc-retained-buttons > .btn { flex: 0 1 auto; }
  .nc-retained-workspace { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 24px; }
  .nc-retained-file { border-left: 1px solid var(--border); padding-left: 24px; }
}
/* Unread: a filled square badge on the card head and in the heading. */
.nc-unread {
  display: inline-flex; align-items: center; gap: 4px; vertical-align: middle;
  font-size: 11px; font-weight: 800; padding: 2px 8px; white-space: nowrap;
  border-radius: var(--radius-sm); background: var(--brand); color: var(--brand-ink);
}
.nc-card-head .nc-unread { margin: 0 auto 0 var(--space-4); }
/* The console's own composer (used until the shared one ships): the counter
   under the box, the refusal under the row. */
.nc-composer { display: flex; flex-direction: column; gap: 4px; }
.nc-composer-main { flex: 1 1 auto; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.nc-composer .chat-input { resize: none; overflow-y: auto; max-height: 180px; }
.nc-chat-count { align-self: flex-end; font-size: 11px; color: var(--ink-muted); font-variant-numeric: tabular-nums; }
.nc-chat-count, .nc-chat-err { min-height: 1.5em; }
.nc-chat-err { margin: 0; font-size: 12.5px; color: var(--danger); }
/* A deep-linked card (« #notaires&acte=… ») flashes once, then rests. */
.nc-card.is-flash { animation: ncFlash 1.6s ease-out both; }
/* The client's offer band flashes the same way when the bell or a deep link lands on it. */
.my-offer-detail.is-flash { animation: ncFlash 1.6s ease-out both; }
@keyframes ncFlash {
  0% { box-shadow: 0 0 0 4px var(--focus-ring); border-color: var(--brand); }
  100% { box-shadow: none; }
}
@media (prefers-reduced-motion: reduce) { .nc-card.is-flash { animation: none; border-color: var(--brand); } }
/* The Retenir sheet: a wider dialog (it reads back a whole engagement), the
   retained card's key/value register, left-rule sections for the terms. */
.nc-retenir-dialog { max-width: 880px; max-height: calc(100dvh - 32px); }
.nc-retenir-dialog[open] { display: flex; flex-direction: column; overflow: hidden; }
.nc-retenir-dialog > .nc-retenir { overflow-y: auto; min-height: 0; overscroll-behavior: contain; }
.nc-retenir-dialog .nc-retenir > h3 { padding-right: 24px; }
.nc-retenir-act { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }
.nc-retenir-svc { font-size: 19px; font-weight: 700; }
.nc-retenir-date { font-size: 13px; color: var(--ink-muted); }
.nc-retenir-date::first-letter { text-transform: uppercase; }
.nc-retenir-signals { margin: 0 0 20px; }
.nc-retenir-columns { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; }
.nc-retenir-section { min-width: 0; padding: 18px 0; border-top: 1px solid var(--border); overflow-wrap: anywhere; }
.nc-retenir-section h4 { margin: 0 0 14px; font-size: 15px; font-weight: 700; color: var(--ink); }
.nc-retenir-section h5 { margin: 16px 0 8px; font-size: 13px; font-weight: 700; color: var(--ink); }
.nc-retenir-kv { grid-template-columns: minmax(100px, 35%) minmax(0, 1fr); gap: 12px; margin: 0; }
.nc-retenir-kv [hidden] { display: none; }
.nc-retenir-kv dd { line-height: 1.5; }
#nc-retenir-fee { display: block; font-size: 24px; line-height: 1.2; font-variant-numeric: tabular-nums; color: var(--ink); }
.nc-retenir-kv .nc-deplacement, .nc-retenir-kv .nc-prefixe, .nc-retenir-kv .nc-lender, .nc-retenir-kv .nc-distance {
  display: inline; padding: 0; border: 0; background: none; font-size: 13px; font-weight: 600; color: var(--ink); white-space: normal;
}
.nc-retenir-sub { color: var(--ink-muted); font-weight: 400; }
.nc-retenir-missing { margin-top: 12px; padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-inset); }
.nc-retenir-missing h5 { margin-top: 0; }
.nc-retenir-count { display: inline-block; margin-left: 8px; font-size: 12px; color: var(--ink-muted); font-variant-numeric: tabular-nums; }
.nc-retenir-checklist, .nc-retenir-factor-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 24px; margin: 0; padding-left: 18px; font-size: 13px; line-height: 1.55; }
.nc-retenir-checklist li, .nc-retenir-factor-list li { padding-left: 2px; }
.nc-retenir-checklist li::marker { color: var(--ink-muted); }
.nc-retenir-details { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 24px; margin: 0; }
.nc-retenir-detail { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border); font-size: 13px; line-height: 1.5; }
.nc-retenir-detail dt { color: var(--ink-muted); }
.nc-retenir-detail dd { margin: 0; font-weight: 600; }
.nc-retenir-more { margin-top: 6px; }
.nc-retenir-footer { flex: none; padding: 12px 22px; border-top: 1px solid var(--border); background: var(--surface); }
.nc-retenir-footer .btn { min-height: 44px; min-width: 0; }
.nc-retenir-error { margin: 0 0 10px; color: var(--danger); font-size: 13px; }
.nc-retenir-sec { margin: 0 0 var(--space-6); padding: 2px 0 2px 10px; border-left: 2px solid var(--border-strong); }
.nc-retenir-sec[hidden] { display: none; }
.nc-retenir-h { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-muted); margin-bottom: 4px; }
.nc-retenir .nc-retenir-p { margin: 0; font-size: 13px; line-height: 1.55; color: var(--ink-muted); }
.nc-retenir .nc-retenir-readiness, .nc-retenir .nc-retenir-appointment { margin: 10px 0 0; }
.nc-retenir .nc-retenir-contact { margin: 0; }
.nc-retenir-bareme { list-style: none; margin: 0 0 var(--space-2); padding: 0; font-size: 13px; }
.nc-bareme-row { display: flex; flex-wrap: wrap; gap: 0 4px; padding: 2px 0; }
.nc-bareme-days { font-weight: 700; font-variant-numeric: tabular-nums; }
.nc-bareme-rate { font-weight: 700; color: var(--ink); }
.nc-bareme-amt { font-weight: 800; color: var(--brand); }
.nc-bareme-free .nc-bareme-rate { color: var(--ok); }
.nc-retenir-dialog .dialog-actions .btn-primary { flex: 1 1 auto; flex-wrap: wrap; }
.nc-retenir-go-amt { white-space: nowrap; }
@media (max-width: 640px) {
  .nc-retenir-columns, .nc-retenir-checklist, .nc-retenir-factor-list, .nc-retenir-details { grid-template-columns: minmax(0, 1fr); }
  .nc-retenir-columns { gap: 0; }
  .nc-retenir-dialog > .nc-retenir { padding: 20px 16px; }
  .nc-retenir-footer { padding: 12px 16px; }
  .nc-retenir-footer .dialog-actions { gap: 8px; }
  .nc-retenir-footer .btn { padding: 10px 12px; }
}
.nc-pay { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border); }
.nc-pay .btn { margin-top: 4px; }
/* Notary earnings roll-up: realised value, the price the CLIENT paid for the
   Nota service, and what the notary keeps — never a cut of their fees. */
.nc-earn { margin-top: 6px; }
.nc-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
.nc-stat { border: 1px solid var(--border); border-radius: var(--radius); padding: 12px 14px; background: var(--surface); }
.nc-stat-v { font-size: 22px; font-weight: 800; letter-spacing: -0.02em; color: var(--ink); }
.nc-stat-k { font-size: 12px; font-weight: 600; color: var(--ink-muted); margin-top: 3px; }
.nc-stat-net { border-color: var(--brand); }
.nc-stat-net .nc-stat-v { color: var(--brand); }
/* Kill the default <p> margins so the empty state + the money facts read as
   one quiet block, not three floating paragraphs. */
.nc-earn .help { margin: 8px 0 0; }

/* --- « Votre cote » (ADR 0028) -------------------------------------------
   The measure of the SERVICE, published whole — since ADR 0031 it decides no
   dollar: the notary keeps 100 % of their fees. The number leads at display
   size; the axes are the arithmetic under it. Square register throughout —
   no pill, no circle; every colour is a token. */
.nc-cote { margin-top: var(--space-3); }
.nc-cote-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-3) var(--space-8); }
.nc-cote-n {
  display: inline-flex; align-items: baseline; gap: var(--space-1);
  padding: var(--space-2) var(--space-6);
  border: 1px solid var(--brand); border-radius: var(--radius);
  background: var(--brand-tint-solid); color: var(--brand);
}
.nc-cote-v { font-size: var(--type-h2); font-weight: 800; letter-spacing: -0.03em; line-height: 1.1; }
.nc-cote-max { font-size: 14px; font-weight: 600; color: var(--ink-muted); }
.nc-cote-head .help { margin: 0; flex: 1 1 240px; }

.nc-cote-axes { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr)); gap: var(--space-5); margin-top: var(--space-6); }
.nc-cote-axe { border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-5) var(--space-6); background: var(--surface); }
.nc-cote-axe-h { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); }
.nc-cote-axe-nom { font-size: 13px; font-weight: 600; color: var(--ink); }
.nc-cote-axe-pts { font-size: 13px; font-weight: 700; color: var(--brand); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* A thin bar, not a gauge: it ranks the four axes at a glance, the figures
   below carry the truth. --radius-xs keeps it in the square register. */
.nc-cote-bar { height: 5px; margin-top: var(--space-3); border-radius: var(--radius-xs); background: var(--surface-inset); overflow: hidden; }
.nc-cote-bar-fill { display: block; height: 100%; border-radius: var(--radius-xs); background: var(--brand-bright); }
.nc-cote-detail { margin-top: var(--space-3); font-size: 12px; line-height: 1.6; color: var(--ink-muted); font-variant-numeric: tabular-nums; }
/* The separator is CSS, never a text node: the figures stay translatable
   fragment by fragment. */
.nc-cote-f + .nc-cote-f::before { content: ' · '; color: var(--border-strong); }

.nc-cote-next { margin: var(--space-6) 0 0; font-weight: 600; color: var(--ink); }
.nc-bareme { margin-top: var(--space-6); border-top: 1px solid var(--border); padding-top: var(--space-5); }
.nc-bareme-h { font-size: 12px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-muted); }
.nc-bareme-row {
  margin-top: var(--space-3); padding: var(--space-2) var(--space-5);
  border-left: 2px solid var(--border); border-radius: var(--radius-xs);
  font-size: 13px; color: var(--ink-muted); font-variant-numeric: tabular-nums;
}
.nc-bareme-row.is-current { border-left-color: var(--brand); background: var(--brand-tint-solid); color: var(--ink); font-weight: 600; }

/* The per-service record, inside « Vos évaluations ». */
.nc-svc { margin-top: var(--space-6); border-top: 1px solid var(--border); padding-top: var(--space-5); }
.nc-svc-h { font-size: 12px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-muted); }
.nc-svc-row { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-3) var(--space-6); margin-top: var(--space-4); }
.nc-svc-nom { font-size: 13px; font-weight: 600; color: var(--ink); }
.nc-svc-actes { font-size: 12.5px; color: var(--ink-muted); font-variant-numeric: tabular-nums; }
.nc-svc-none { font-size: 12.5px; color: var(--ink-muted); font-style: italic; }

/* The act-by-act statement: the full disclosure, act by act. Wide content
   scrolls inside its own box — the console never scrolls sideways. */
.nc-actes { margin-top: var(--space-5); overflow-x: auto; }
.nc-actes-table { width: 100%; border-collapse: collapse; font-size: 12.5px; font-variant-numeric: tabular-nums; }
.nc-actes-table th, .nc-actes-table td { padding: var(--space-3) var(--space-5); text-align: left; border-bottom: 1px solid var(--border); white-space: nowrap; }
.nc-actes-table thead th { font-size: 11px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-muted); }
.nc-acte-num { text-align: right; }
.nc-acte-net { font-weight: 700; color: var(--brand); }
.nc-acte-total th, .nc-acte-total td { border-bottom: 0; border-top: 2px solid var(--border-strong); font-weight: 700; color: var(--ink); }
/* ADR 0029 — a line settled OFF the platform. The money never reached Nota and
   the service fee is still owed, so the net must not read as money banked: the
   figure drops out of brand ink into the quiet register the rest of the row
   speaks in. No new shape, no new colour — the same weight, one tone down. */
.nc-actes-table .nc-acte-row[data-paye='false'] .nc-acte-net { color: var(--ink-muted); }
/* The marker stacks UNDER the act's name inside a `white-space: nowrap` cell,
   so it has to opt back into wrapping and take a measure of its own — without
   one it sets the column's width and pushes the money columns off the box. */
.nc-acte-etat { white-space: normal; max-width: 30ch; }
/* « Frais de service à percevoir » is a total that has NOT been settled. It
   keeps the totals row's geometry but steps down twice — a hairline instead of
   the strong rule, muted instead of full ink — so the eye reads it as an
   appendix to the settled totals rather than a sixth column of takings. */
.nc-acte-du th, .nc-acte-du td { border-top: 1px solid var(--border); color: var(--ink-muted); }
.nc-actes .help { margin: var(--space-4) 0 0; }

/* --- Demonstration data, declared ---------------------------------------
   store.listMonth falls back to domain fixtures when the API is unreachable.
   That is legitimate; being indistinguishable from the real market is not.
   The register is deliberately NOT an alarm — --warn carries "read this",
   --danger would carry "something broke". Square, tokens only. */
.demo-banner {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2) var(--space-5);
  margin: var(--space-5) auto 0; width: min(1200px, calc(100% - var(--space-12)));
  padding: var(--space-4) var(--space-7);
  border: 1px solid var(--border); border-left: 3px solid var(--warn);
  border-radius: var(--radius); background: var(--surface-inset);
}
.demo-banner[hidden] { display: none; }
.demo-banner-t { font-size: 12.5px; font-weight: 800; letter-spacing: 0.02em; color: var(--warn); }
.demo-banner-b { font-size: 12.5px; line-height: 1.5; color: var(--ink-muted); }

/* The per-region mark: an aggregate figure is never bare. Small, quiet, and
   right where the numbers are. */
.demo-mark {
  display: inline-block; padding: 0 var(--space-3);
  border: 1px solid var(--warn); border-radius: var(--radius-sm);
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.04em;
  line-height: 16px; white-space: nowrap; vertical-align: middle;
  color: var(--warn); background: var(--surface);
}

/* Mark slots: they take no room until a mark lands in them. */
.nc-live-head:empty, .onb-live-host:empty { display: none; }
.nc-live-head, .onb-live-host { margin: 0 0 var(--space-4); }
.day-head .demo-mark { margin-left: var(--space-4); }

/* The offline "publication" note: nothing left the device. */
.demo-note {
  margin: var(--space-4) 0 0; padding: var(--space-4) var(--space-5);
  border-left: 3px solid var(--warn); border-radius: var(--radius-xs);
  background: var(--surface-inset);
  font-size: 12.5px; line-height: 1.55; color: var(--ink-muted);
}

/* --- Privacy (Law 25) list ---------------------------------------------- */
/* Two-column on wide screens so the long-form list fills the panel width
   (readable measure per item) instead of leaving a big blank right side. */
.privacy-list { list-style: none; margin: 4px 0 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(330px, 100%), 1fr)); gap: 12px 32px; align-content: start; }
.privacy-list li { position: relative; padding-left: 20px; font-size: 14px; line-height: 1.5; color: var(--ink-muted); }
.privacy-list li strong { color: var(--ink); }
.privacy-list li::before {
  content: ''; position: absolute; left: 0; top: 8px; width: 8px; height: 8px;
  border-radius: var(--radius-xs); background: var(--brand);
}
/* --- Security and compliance -------------------------------------------
   A quiet trust block: one outer surface, with no stack of nested borders or
   certification-looking badges. The wording deliberately distinguishes an
   active programme from a completed audit. */
.compliance-section {
  margin-top: var(--space-8); padding: clamp(20px, 3vw, 28px);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--surface-inset);
}
.compliance-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 20px;
}
.compliance-head .eyebrow { display: block; margin-bottom: 6px; }
.compliance-head h2 { max-width: 680px; margin: 0; }
.compliance-head p { max-width: 760px; margin: 10px 0 0; color: var(--ink-muted); font-size: 14px; line-height: 1.55; }
.compliance-status {
  flex: none; display: inline-flex; align-items: center; min-height: 32px;
  padding: 6px 11px; border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--brand) 12%, var(--surface));
  color: var(--brand); font-size: 12px; font-weight: 800;
  white-space: nowrap;
}
.compliance-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px; margin-top: 20px;
}
.compliance-card {
  display: flex; flex-direction: column; justify-content: center; gap: 4px;
  min-width: 0; min-height: 70px; padding: 14px 16px;
  border-radius: var(--radius); background: var(--surface);
}
.compliance-card strong { color: var(--ink); font-size: 15px; line-height: 1.25; overflow-wrap: anywhere; }
.compliance-card span { color: var(--ink-muted); font-size: 13px; line-height: 1.3; }
.compliance-note { margin: 16px 0 0; color: var(--ink-muted); font-size: 12px; line-height: 1.5; }
@media (max-width: 680px) {
  .compliance-head { display: block; }
  .compliance-status { margin-top: 14px; }
  .compliance-grid { grid-template-columns: 1fr; gap: 8px; }
  .compliance-card { min-height: 0; }
}
/* The legal panes' version line: an unreviewed draft says so, and when it changed. */
.legal-stamp { margin: var(--space-4) 0 0; font-size: 12px; font-weight: 600; letter-spacing: .01em; color: var(--ink-muted); }

/* Notary cards cascade in like agenda rows; disabled under reduced-motion */
.nc-card { animation: rowIn var(--motion-fast) var(--ease-ui) both; }

@media (max-width: 480px) {
  .nc-kv { grid-template-columns: 1fr; gap: 1px 0; }
  .nc-kv dd { margin-bottom: 6px; }
}

/* Le tapis général. Il est !important, donc toute LIGNE TENUE (registre plus
   haut) doit répondre !important elle aussi — c'est le seul endroit du
   registre où c'est inévitable, et un test le vérifie. */
.hidden, [hidden] { display: none !important; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

.tab-pane { display: none; }
.tab-pane.is-active { display: block; animation: paneInForward var(--motion-ui) var(--ease-ui) both; }
.tab-pane.is-active > .wrap, .tab-pane.is-active > .layout { will-change: transform, opacity; }
html[data-nav-direction='back'] .tab-pane.is-active { animation-name: paneInBack; }

/* ==========================================================================
   Motion — subtle micro-interactions. All disabled under reduced-motion.
   ========================================================================== */
@keyframes paneIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes paneInForward { from { opacity: 0; transform: translateX(6px); } to { opacity: 1; transform: none; } }
@keyframes paneInBack { from { opacity: 0; transform: translateX(-6px); } to { opacity: 1; transform: none; } }
/* Nav active indicator: accent line grows from zero width under the selected tab. */
@keyframes navIndicator { from { width: 0; opacity: 0; } to { width: 60%; opacity: 1; } }
/* Drawer item stagger: each row slides up and fades in. */
@keyframes menuItemIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes navIndicatorIn { from { opacity: 0; transform: scaleX(.45); } to { opacity: 1; transform: scaleX(1); } }
@keyframes dialogIn { from { opacity: 0; transform: translateY(10px) scale(.97); } to { opacity: 1; transform: none; } }
@keyframes backdropIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes rowIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@keyframes pop { 0% { transform: scale(.9); } 60% { transform: scale(1.04); } 100% { transform: scale(1); } }
@keyframes sheetUp { from { transform: translateY(100%); } to { transform: translateY(0); } }

/* A dialog opens on the same curve a pane does. It used to carry its own
   cubic-bezier(.2,.8,.2,1), so modals and sections did not move alike. */
dialog[open] { animation: dialogIn var(--motion-ui) var(--ease-ui) both; }
dialog[open]::backdrop { animation: backdropIn var(--motion-ui) var(--ease-ui) both; }
.bid-row { animation: rowIn var(--motion-fast) var(--ease-ui) both; }
.gauge-fill { transition: width var(--motion-enter) var(--ease-ui); }
.dossier-bar > span { transition: width var(--motion-enter) var(--ease-ui); }
.dossier-check { transition: background var(--motion-fast), border-color var(--motion-fast), transform var(--motion-fast); }
.dossier-check[data-on='true'] { animation: pop var(--motion-fast) var(--ease-ui); }
.btn, .nav-tab, .icon-btn, .cal-cell, .pill { transition: background var(--motion-fast), border-color var(--motion-fast), color var(--motion-fast), transform var(--motion-fast), box-shadow var(--motion-fast); }
.card { transition: transform var(--motion-fast), box-shadow var(--motion-fast), border-color var(--motion-fast); }
.card:hover { transform: translateY(-2px); border-color: var(--border-strong); box-shadow: var(--shadow); }

/* Layered entrance — the landing plays like the brand films: the headline
   cascades in with a breath of blur, the market card pops with overshoot,
   feed rows stack in, reward amounts glow once. Panes are display:none when
   inactive, so the sequence replays on each door the visitor walks through.
   Inside .intro--hero the cascade must run on .intro-main's CHILDREN (the
   eyebrow/h1/p live one level down), so the column itself stays still. */
@keyframes fadeUp { from { opacity: 0; transform: translateY(7px); } to { opacity: 1; transform: none; } }
@keyframes heroIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes cardPop { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes amtGlow { 0%, 100% { text-shadow: none; } 50% { text-shadow: 0 0 7px color-mix(in srgb, var(--brand-bright) 22%, transparent); } }
.intro > *, .intro--hero .intro-main > * { animation: heroIn var(--motion-enter) var(--ease-ui) both; }
.intro--hero > .intro-main { animation: none; }
.intro .eyebrow { animation-delay: .04s; }
.intro h1 { animation-delay: .12s; }
.intro p { animation-delay: .24s; }
.intro .hero-cta { animation-delay: .36s; }
/* The market pulse is the films' demand card: it pops, then its rows stack. */
.intro--hero .pulse { animation: cardPop var(--motion-enter) var(--ease-ui) var(--motion-enter) both; }
.pulse-rows > * { animation: fadeUp var(--motion-enter) var(--ease-ui) both; }
.pulse-rows > *:nth-child(2) { animation-delay: .08s; }
.pulse-rows > *:nth-child(3) { animation-delay: .16s; }
.pulse-rows > *:nth-child(4) { animation-delay: .24s; }
/* Notaires: the live open demands stagger in like the film's feed. */
.nc-live-grid > * { animation: fadeUp var(--motion-enter) var(--ease-ui) both; }
.nc-live-grid > *:nth-child(2) { animation-delay: .09s; }
.nc-live-grid > *:nth-child(3) { animation-delay: .18s; }
.nc-live-grid > *:nth-child(4) { animation-delay: .27s; }
.cards .card { animation: fadeUp var(--motion-enter) var(--ease-ui) both; }
.cards .card:nth-child(2) { animation-delay: .08s; }
.cards .card:nth-child(3) { animation-delay: .16s; }

/* ENTRÉES AU DÉFILEMENT — un registre PARTAGÉ par les portes (2026-09-20).
   `.reveal` n'a d'effet que si le script a posé `html.has-reveal` (wireReveal,
   app.js) : sans script, sans IntersectionObserver ou en mouvement réduit, rien
   n'est jamais caché. Un bloc monte de --space-6 et s'éclaircit sur le barreau
   des entrées ; ses enfants marqués `--reveal-i` suivent à --menu-stagger.
   `.accent-line` est le trait d'accent de 3 px du guide (brand.html, « Le trait
   d'accent ») qui se TRACE de gauche à droite à l'arrivée du bloc : droit,
   plein, arrêté au bord du conteneur — la carte le rogne à ses coins. */
.has-reveal .reveal { opacity: 0; transform: translateY(var(--space-6)); }
.has-reveal .reveal.is-in { opacity: 1; transform: none; transition: opacity var(--motion-enter) var(--ease-ui), transform var(--motion-enter) var(--ease-ui); transition-delay: calc(var(--reveal-i, 0) * var(--menu-stagger)); }
.accent-line { position: relative; overflow: hidden; }
.accent-line::before { content: ''; position: absolute; inset: 0 0 auto; height: 3px; background: var(--accent-line, var(--action-ink)); transform-origin: left center; transition: transform var(--motion-enter) var(--ease-ui); transition-delay: calc(var(--motion-ui) + var(--reveal-i, 0) * var(--menu-stagger)); }
.has-reveal .reveal:not(.is-in) .accent-line::before, .has-reveal .reveal.accent-line:not(.is-in)::before { transform: scaleX(0); }
/* `.reveal-1` … `.reveal-6` posent le rang d'une cascade (--reveal-i ×
   --menu-stagger) sur un bloc `.reveal` ou sur un enfant tracé ; la variable
   s'hérite. `.rail-draw` est le MONTANT d'une échelle : un filet vertical de
   2 px (le « séparateur » du guide) qui se TRACE de haut en bas à l'arrivée de
   son bloc `.reveal` — par clip-path, pour qu'un pointillé se découvre sans
   s'étirer ; l'appelant le place par --rail-x / --rail-top / --rail-bottom, et
   `.rail-draw--goal` le tire en pointillé : un objectif, pas un acquis. */
.reveal-1 { --reveal-i: 1; } .reveal-2 { --reveal-i: 2; } .reveal-3 { --reveal-i: 3; }
.reveal-4 { --reveal-i: 4; } .reveal-5 { --reveal-i: 5; } .reveal-6 { --reveal-i: 6; }
.rail-draw { position: relative; }
.rail-draw::after { content: ''; position: absolute; left: var(--rail-x, 0); top: var(--rail-top, 0); bottom: var(--rail-bottom, 0); width: 2px; background: var(--rail-ink, var(--action-ink)); clip-path: inset(0); transition: clip-path var(--motion-enter) var(--ease-ui); transition-delay: calc(var(--motion-ui) + var(--reveal-i, 0) * var(--menu-stagger)); }
.rail-draw--goal::after { background: repeating-linear-gradient(to bottom, var(--rail-ink, var(--action-ink)) 0 var(--space-2), transparent var(--space-2) var(--space-4)); }
.has-reveal .reveal:not(.is-in) .rail-draw::after, .has-reveal .reveal.rail-draw:not(.is-in)::after { clip-path: inset(0 0 100% 0); }
/* `.stroke-draw` : un glyphe au trait qui se DESSINE à l'arrivée de son bloc
   `.reveal`. Chaque forme du SVG porte pathLength="1" : un seul tiret de
   longueur 1 suffit alors à toutes, quelle que soit leur taille. L'état final
   (décalage 0) est le glyphe entier — c'est aussi l'état sans script. */
.stroke-draw :is(path, rect, circle, line) { stroke-dasharray: 1; stroke-dashoffset: 0; transition: stroke-dashoffset var(--motion-enter) var(--ease-ui); transition-delay: calc(var(--motion-enter) + var(--reveal-i, 0) * var(--menu-stagger)); }
.has-reveal .reveal:not(.is-in) .stroke-draw :is(path, rect, circle, line) { stroke-dashoffset: 1; }
@media (prefers-reduced-motion: reduce) {
  .tab-pane.is-active, .intro > *, .intro--hero .intro-main > *, .intro--hero .pulse,
  .pulse-rows > *, .nc-live-grid > *, .cards .card { animation: none; }
  dialog[open] .dialog-pad > *, dialog[open] .auth-body > *, dialog[open] .onb-body > *,
  .acct-action, .acct-panel { animation: none !important; }
  html { scroll-behavior: auto; }
}
/* Mobile performance (propriétaire, 2026-09-16) : les écrans tactiles n'ont
   pas de survol — le translateY(-1px) des cartes déclenche un flash visible
   au toucher. Les GPU mobiles paient cher les will-change et backdrop-filter. */
@media (pointer: coarse) {
  .nc-card:hover { transform: none; box-shadow: none; }
}
@media (max-width: 768px) {
  .tab-pane.is-active > .wrap, .tab-pane.is-active > .layout { will-change: auto; }
  .nc-live-grid > * { animation-delay: 0s !important; }
  .mark-drift--site { opacity: .2; }
}
@media (max-width: 480px) {
  .mark-drift--site { display: none; }
}

/* More hover micro-interactions across client surfaces */
.bid-row { transition: background-color var(--motion-fast) var(--ease-ui); }
.bid-row:hover { background: var(--action-tint); }
.dossier-item { transition: background-color var(--motion-fast) var(--ease-ui); }
.dossier-item:hover { background: var(--action-tint); }
.legend-item { transition: color var(--motion-fast) var(--ease-ui); }
.brand-mark img, .brand-mark-svg { transition: transform var(--motion-fast) var(--ease-ui); }
.brand:hover .brand-mark img, .brand:hover .brand-mark-svg { transform: translateY(-1px); }

/* Subscribe card — borderless floating panel (white surface, soft shadow):
   the "Le carnet dans votre agenda" band on the Notaires page. */
.sub-card {
  background: var(--surface-veil);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: var(--pad-card-lg);
}
.sub-card-head { display: flex; align-items: center; gap: 11px; }
.sub-card-logo { flex: none; display: grid; place-items: center; }
.sub-card-logo img { display: block; }
.sub-card-kicker { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--subtitle-ink); margin-bottom: 3px; }
.sub-card-title { font-weight: 700; font-size: 13.5px; line-height: 1.2; }
.sub-card-sub { font-size: 12px; color: var(--ink-muted); margin-top: 2px; line-height: 1.45; }
.calendar-subscription-field { display: grid; gap: 6px; margin: 10px 0; }
.calendar-subscription-field input { width: 100%; min-width: 0; }
.calendar-subscription-field .btn { justify-self: start; }
.sub-card-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.sub-card-actions .btn { flex: 1 1 auto; gap: 6px; padding-left: 10px; padding-right: 10px; }
.brand-ic { flex: none; display: block; }

/* The manual subscription link lives in the ICS modal (#sub- / #notary-
   subscription-dialog); the inline disclosure that used to hold it is gone. */
.calendar-subscription-field label { color: var(--ink-muted); font-size: 11px; font-weight: 700; }
.subscription-input-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 8px; }
.subscription-input-row input { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.subscription-input-row .btn { justify-self: stretch; white-space: nowrap; }
/* Reserve the longest phone recovery message so the centred modal and its
   controls stay still as copying moves between pending, success and failure. */
.dialog-pad .calendar-subscription-status { min-block-size: 4.5em; font-size: var(--type-body); line-height: var(--type-body-lh); margin-block: var(--space-2) 0; }
.sub-card-footnote { margin: 12px 0 0; padding-top: 10px; border-top: 1px solid var(--border); }

@media (max-width: 520px) {
  .sub-card-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sub-card-actions .btn { min-width: 0; }
}
@media (max-width: 400px) {
  .subscription-input-row { grid-template-columns: 1fr; }
  .subscription-input-row .btn { width: 100%; }
}
.nc-card-actions .mini-btn { margin-left: auto; }
/* Compact card everywhere: on the signed-out landing the grid places it in
   the right column under the gate; signed-in it keeps this small step down. */
/* Borderless notification bell in the header. */

/* Calendar loading: an indeterminate top bar while the carnet fetches (real
   latency on the live API). Scoped to the carnet panel; overlay only. */
#carnet-panel { position: relative; }
#carnet-panel.is-loading { pointer-events: none; }
#carnet-panel.is-loading::after {
  content: ''; position: absolute; top: 0; left: -40%; height: 2px; width: 40%;
  background: var(--brand-bright); border-radius: var(--radius-xs);
  box-shadow: 0 0 8px var(--brand-bright);
  animation: loadbar 1.05s ease-in-out infinite;
}
#carnet-panel.is-loading #cal-grid, #carnet-panel.is-loading #agenda { opacity: .55; transition: opacity var(--motion-fast); }
@keyframes loadbar { 0% { left: -40%; } 55% { left: 62%; } 100% { left: 100%; } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
}

/* ==========================================================================
   Responsive — mobile / tablet / desktop, no horizontal overflow anywhere.
   ========================================================================== */
@media (max-width: 900px) {
  /* 14 top / 4 bottom inverted the desktop asymmetry and let the market copy
     nearly touch the calendar card. */
  .intro { padding-block: var(--space-7); }
}
/* THE HERO'S TWO-COLUMN THRESHOLD, and everything that follows from it.
   Below this the market panel cannot sit beside the copy, so it stacks under
   it. 768px is where two columns still leave the pulse ~340px: enough for the
   act name, its two fr-CA amounts ("1 250 $ · 1 950 $") AND the volume bar on
   one row. At 720–767 a column is ~300px, and the amounts painted over the
   bar and each other — prices must never jam, so the hero stacks instead.

   Below it the pitch is trimmed: the eyebrow goes (the h1, the tagline and
   the two CTAs still say what this is) and the market panel keeps its
   FIGURES and drops its counts caption, so the carnet lands near the fold. */
/* 768–900 — the copy still holds two columns; the market strip beside it does
   not. The threshold below was measured in English: in French a half-column at
   768 leaves the strip ~330px, and « repère du mois » over « 2 279 $ » ran 19px
   under the book arrow while the kicker painted over the month. So the strip
   takes the WHOLE width under the copy from 900 down, which is what the rules
   two blocks up have claimed since they were written. Everything else stays
   desktop here — the eyebrow, the gauges, the counts caption; the phone's
   two-card strip still starts below 768. */
@media (min-width: 768px) and (max-width: 899.98px) {
  .intro--hero { grid-template-columns: 1fr; gap: clamp(18px, 3vw, 26px); }
}
@media (max-width: 767.98px) {
  .intro--hero { grid-template-columns: 1fr; gap: clamp(18px, 3vw, 26px); }
  /* The tagline (and the notary lede) IS the phone copy; only the eyebrow goes. */
  .intro .eyebrow { display: none; }
  /* Side by side rather than stacked. */
  .hero-cta { flex-direction: row; flex-wrap: wrap; }
  /* Size to content — no text wrapping inside buttons. They stack on narrow screens. */
  .hero-cta .btn { flex: 0 1 auto; white-space: nowrap; }
  /* THE PHONE MARKET STRIP (owner, 2026-08-27: « pour la version mobile,
     financing et refinancing, on peut utiliser un autre UI — le but c'est de
     focusser sur les availabilities et le calendrier »). The stacked rows
     cost ~300px of the first screen and pushed the calendar under the fold;
     the two acts now sit SIDE BY SIDE as a pair of compact cards — the act's
     name over its two captioned figures. The volume bar and the counts
     caption stay desktop-only (market colour, not a booking decision), and
     the per-row book arrow goes: the hero CTA right above already books.
     Same DOM as the desktop rows — a card still filters the carnet below,
     and the active act keeps .is-on, indicated by its underlined name. */
  .pulse-rows { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
  /* The item wrapper dissolves so each ROW is the grid child; its book arrow
     is display:none, so nothing else surfaces from the wrapper. */
  .pulse-item { display: contents; }
  .pulse-item .mini-btn { display: none; }
  /* Compact filters retain their own spacing on phones. */
  .pulse-item .pulse-row { padding: 10px 12px; margin: 0; }
  .pulse-row {
    display: flex; flex-direction: column; align-items: stretch; gap: 7px;
  }
  .pulse-svc { font-size: clamp(12px, 3.5vw, 13.5px); }
  /* The captions STAY: two bare amounts stacked read as one confusing price.
     Each figure takes a full line of its card — caption left, amount right. */
  .pulse-figs { flex-direction: column; align-items: stretch; gap: 3px; }
  /* « repère du mois » + a five-figure amount do not fit one 115px line at
     320px: let the amount drop under its caption instead of past the card. */
  .pulse-fig { flex-direction: row; flex-wrap: nowrap; justify-content: space-between; align-items: baseline; gap: 8px; min-width: 0; }
  .pulse-fig-k { font-size: 10.5px; }
  .pulse-fig-v { font-size: 14px; }
  .pulse-bar, .pulse-meta { display: none; }
  /* The floating « Comment ça marche » bubble goes on phones (owner,
     2026-08-27: « remove this ») — it sat over the calendar tiles on the
     very screen the phone now centres on. The guide keeps its phone doors:
     the first-visit onboarding and the footer link. Desktop keeps the
     bubble, one tap from anywhere. (ADR 0022 §3 — a « polish » commit and a
     consolidation carry-over both flipped this back to inline-flex; the
     bubble then sat on the notary calendar's month grid at 390 px.) */
  .guide-fab { display: none; }
}

/* At phone widths, give the offering strip one calm reading column. Two
   narrow cards force both the service name and the caption/value pair onto
   extra lines (especially « Power of attorney » and « month’s reference »).
   One wider card keeps each fact on one line and lets the four acts scan as a
   consistent list without clipping or ellipses. */
@media (max-width: 480px) {
  .pulse-head {
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
  }

  .pulse-rows { grid-template-columns: minmax(0, 1fr); }
  .pulse-fig { flex-wrap: nowrap; }
  .pulse-head { display: flex; }
  .pulse-svc { white-space: nowrap; }
}
/* The DRAWER threshold is 900: above it the header carries the full control
   set (compact band 900–1099.98); below it everything hands off to the
   hamburger — the narrow header is brand → avatar → burger. Theme and language
   keep their drawer rows (#mnav-theme / #mnav-lang), so hiding them here
   loses nothing; the guide « ? » is the fixed bubble on desktop and the
   footer link / first-visit guide on phones (see ux-nav.test.mjs). */
@media (max-width: 899.98px) {
  .nav-burger { display: grid; }
  .nav-tabs, .header-auth, #theme-toggle { display: none; }
  #lang-toggle { display: none; }
  /* Language and theme move to the drawer; voice remains a direct action. */
  .header-tools { display: inline-flex; padding: 0; background: transparent; }
  .header-tools > * + *::after { display: none; }
  .header-voice-label { display: none; }
  .header-voice-btn { min-width: 44px; min-height: 44px; padding: 0; justify-content: center; }
}

/* ==========================================================================
   Quiet arrival refinement
   The first decision should feel like a calm welcome: the mark carries the
   identity, the two paths remain obvious, and the surrounding motion stays
   peripheral. Language detection remains active in i18n.js; only its chrome
   is removed from the visual layout.
   ========================================================================== */
@keyframes igChooserReveal {
  from { opacity: 0; transform: translateY(12px) scale(.985); }
  to { opacity: 1; transform: none; }
}

/* Keep the language API, URL override and keyboard coverage intact while the
   product presents one quiet browser-selected language by default. */
.language-control { opacity: 0 !important; pointer-events: auto !important; }
#lang-toggle.language-control {
  position: relative !important;
  top: auto; right: auto; width: 1px; height: 1px;
  margin: 0; padding: 0; overflow: visible; border: 0;
  z-index: 1;
}
.mnav-pref.language-control {
  min-height: 1px; height: 1px; margin-block: -1px !important; overflow: visible;
}

/* Consent is still explicit, but reads as a small preference notice instead
   of a dominant bottom panel. */
.analytics-consent {
  left: 50%; right: auto; bottom: 16px;
  width: min(560px, calc(100vw - 32px)); max-width: none;
  padding: 12px 14px;
  transform: translateX(-50%);
  background: var(--surface);
  border-color: var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.analytics-consent p { margin-bottom: 8px; font-size: 12px; line-height: 1.45; }
.analytics-consent button, #analytics-preferences:not(.footer-link) { padding: 7px 10px; margin-right: 4px; font-size: 12px; }
.analytics-consent a { font-size: 12px; }

/* The transient toast follows the same low-contrast language as the consent
   notice and never competes with a form or a confirmation action. */
.toast {
  bottom: 18px;
  padding: 10px 14px;
  background: var(--brand);
  color: var(--brand-ink);
  border: 1px solid color-mix(in srgb, var(--brand-ink) 18%, transparent);
  box-shadow: var(--shadow-brand);
  font-size: 13px;
}

/* Above the drawer threshold the drawer can never appear, open class or not. */
@media (min-width: 900px) {
  .mnav, .mnav-scrim { display: none; }
}

@media (max-width: 680px) {
  /* THE LEGEND WAS ONE CRAMMED PARAGRAPH. Everything lived in a single
     wrapping flex row, so "SERVICE" landed mid-line right after "Extreme 8x"
     with a vertical rule in front of it, reading as one run-on block. Each
     label now takes its own line and its keys wrap underneath it, and the rows
     get room to breathe. */
  .legend { gap: var(--space-4) var(--space-5); }
  .legend-label { flex: 1 0 100%; margin-top: var(--space-2); }
  /* The rule and the indent only make sense inline, which it no longer is. */
  .legend-label--sep { margin-left: 0; padding-left: 0; border-left: 0; }
  /* Four lines restating what the cell already prints, on the screen with the
     least room for it. */
  .legend-note { display: none; }

  /* Longhand: a shorthand would reset .layout's vertical padding to 0 and the
     carnet would butt against the hero and against the footer. */
  .wrap { padding-inline: var(--space-8); }
  .site-header .wrap { gap: 8px; } /* height follows --header-h below */
  /* The header shrinks here, so the scroll offset it feeds must shrink with it,
     or a scrolled-to cell lands under the header instead of below the gap. */
  :root { --header-h: 56px; --sticky-top: 76px; }
  .brand { --lockup-tile: 32px; font-size: 17px; }
  .nav-tab { padding: 6px 9px; font-size: 13px; }
  .intro h1 { font-size: var(--type-h1-compact); }
  /* No padding here. The cal container queries own cell padding, and a
     viewport rule this late in the file silently outranks all of them. */
  /* No min-height: @container cal owns cell sizing, and a viewport rule this
     far down the file outranks it at equal specificity. */
  /* .cal-avg deliberately has NO font-size here. The container query compacts it
     by zeroing the font and reprinting attr(data-compact) from ::after; a
     viewport rule that restores a visible size cannot remove the ::after, so the
     two used to print together as "3 285 $3,3k". Sizing belongs to the container
     queries, which is what this cell's content responds to anyway. */
    /* Sides stay at 14 so the grid lines up with the toolbar, filter bar and
     legend that bracket it inside the same card. */
  /* Padding only. gap:4px here outranked the 3-column reflow's own gap, so
     the phone grid packed 2px tighter than the token chose. */
  .cal-grid { padding: var(--space-4) var(--space-7) var(--space-6); }

  .cal-row { gap: 4px; }
  .cal-dow { font-size: 10px; }
  .filters { padding: 10px 14px; gap: 8px; }
  .field { flex: 1 1 40%; }
  /* :not(.visually-hidden): this attribute selector outranks the class, and a
     full-width HIDDEN date input was silently widening the booking sheet's
     scroll box by 16px on phones. */
  select:not(.visually-hidden), input[type='text'], input[type='email'], input[type='tel'], input[type='number'], input[type='date']:not(.visually-hidden) { min-width: 0; width: 100%; }
  /* Phone: the lender dropdown stretches with its sheet like every other field. */
  .crit-row .nselect { max-width: none; }
  .cards { grid-template-columns: 1fr; }
  .section { padding: 28px 0; }
  #day-dialog, dialog { width: 96vw; }
  /* The day-booking dialog becomes a bottom sheet on phones (thumb-reachable,
     slides up). Ordered after the 96vw rule so width:100% wins. */
  #day-dialog { margin: 0; inset: auto 0 0 0; width: 100%; max-width: 100%; max-height: 92dvh; border-radius: var(--radius-lg) var(--radius-lg) 0 0; }
  #day-dialog[open] { animation: sheetUp var(--motion-ui) var(--ease-ui) both; }
  .day-head { padding: 16px 60px 10px 16px; }
  /* The offer rows shrink with the bands that bracket them; the 2px difference
     compensates .bid-row's own left border. */
  .day-bids .bid-row { padding-left: 14px; padding-right: var(--space-8); }
  .day-bids-count { padding-left: var(--space-8); padding-right: var(--space-8); }
  .day-book { padding: 14px 16px 18px; }
  /* The day dialog becomes a full-width sheet on phones, so its rows are as tight
     as the list cards — give them the same two-line treatment. */
  .day-bids .bid-row { flex-wrap: wrap; row-gap: 3px; }
  .day-bids .bid-amount { order: 1; }
  .day-bids .pill, .day-bids .status-chip { order: 2; }
  .day-bids .bid-meta { order: 4; flex: 1 0 100%; }
  .day-bids .status-chip { max-width: none; }
  /* Explainer stacks the badge over the text on narrow screens. */
  .hero-cta { gap: 8px; }
  .hero-cta .btn-lg { flex: 1 1 auto; }
  /* (Auth buttons left the narrow header entirely — they live in the
     hamburger drawer below 900px.) */
}
/* (The theme toggle leaves the header with the tabs at 899.98px — it lives in
   the hamburger drawer on phones, so it stays reachable at every width.) */
/* Smallest phones (320-360): the header wordmark yields to the logo mark, which
   stays the home affordance. Scoped to the header — the footer reuses
   .brand-word and has room for it. */
@media (max-width: 360px) {
  .site-header .brand-sub { display: none; }
  .site-header .brand-word { display: none; }
}
/* Comfortable touch targets on phones (>=44px), gated to coarse pointers so the
   desktop density is untouched. */
/* Comfortable 44px touch targets on ANY coarse pointer (phones AND tablets, e.g.
   iPad portrait at 768) — not width-gated. Fine pointers (mouse/trackpad) keep the
   desktop density untouched. Includes the smaller controls that were being missed. */
@media (pointer: coarse) {
  .btn, .nav-tab, .chip, .seg-btn, .acct-item, .acct-legal-link, input[type='range'], .nselect-btn { min-height: 44px; }
  /* Le sélecteur FR|EN et l'interrupteur de thème (.mini-seg-btn) manquaient à
     l'appel (2026-09-06) : sur téléphone l'en-tête les range dans le tiroir, et
     ils y tenaient 35 × 24 px — sous la cible tactile, pour le seul geste qui
     change la langue de tout le site. La piste garde sa hauteur d'origine à la
     souris ; au doigt, les deux boutons montent à 44. */
  .mini-seg-btn { min-height: 44px; }
  /* Et la piste suit : à 28 px de haut elle laissait ses propres boutons
     dépasser de 8 px en haut et en bas. 44 + les deux marges de 2. */
  .mini-seg { height: 48px; }
  .nselect-opt { min-height: 44px; display: flex; align-items: center; }
  /* Repeated at .header-auth .btn specificity: the ≤680px header rule sets a
     32px floor on the SAME selector, and on a phone (coarse + narrow) it was
     out-ranking the plain .btn floor above — leaving the only sign-up button
     under the 44px touch target. */
  .header-auth .btn { min-height: 44px; }
  /* Clickable notification rows and their dismiss ✕ join the 44px floor; the
     row's right padding grows so text never slides under the bigger target. */
  .notif-item[role='button'] { min-height: 44px; }
  .notif-item { padding-right: 48px; }
  .notif-x { width: 44px; height: 44px; top: 2px; right: 0; }
  /* Footer links and the brand are plain <a>s (~20px tall) — they need the same
     thumb-sized hit area as the buttons above. inline-flex so the gap-based
     footer row keeps its alignment. */
  .site-footer a, .brand { min-height: 44px; display: inline-flex; align-items: center; }
  /* « Comment ça marche » is a BUTTON among those links (it opens the guide
     dialog), so the rule above never reached it — and on a phone, where the
     « ? » bubble is deliberately absent (ADR 0022), the footer is the only
     door left to the guide. It was 26px tall. */
  .site-footer .footer-link { min-height: 44px; display: inline-flex; align-items: center; }
  /* A text field is a touch target like any other: the pane's own inputs came
     out 42px from their padding alone, two short of the promise. */
  input[type='text'], input[type='email'], input[type='tel'], input[type='number'],
  input[type='search'], input[type='password'], input[type='date'], textarea { min-height: 44px; }
  .mini-btn { width: 44px; height: 44px; }
  .cal-nav .btn { min-width: 44px; }
  /* flex:none — in the drawer head the lockup grew and squeezed the close
     button to 32px wide (android lens, 2026-09-11); a thumb target does not shrink. */
  .icon-btn { width: 44px; height: 44px; flex: none; }
  /* « Offrir autant · N $ » is a 26px text button on the booking sheet; it only
     appears when the day already has an offer, which is why the lens caught it
     in CI and not locally. A thumb target is 44px whatever the data. */
  .day-beat { min-height: 44px; }
}
@media (max-width: 420px) {
  .nav-tabs { gap: 0; }
  .nav-tab { padding: 6px 7px; font-size: 12px; }
  /* .cal-cell and .cal-daynum are sized by @container cal, not from here. */
}

/* Never let the page scroll sideways */
html { max-width: 100%; overflow-x: hidden; overflow-x: clip; }
body { max-width: 100%; overflow-x: hidden; overflow-x: clip; }
/* Smooth scrolling centralized in CSS (so the reduced-motion reset above wins),
   and every anchored/focus/programmatic scroll stops BELOW the sticky header. */
html { scroll-behavior: smooth; scroll-padding-top: var(--sticky-top); }

/* ==========================================================================
   Carnet view switcher (Calendrier · Liste)
   ========================================================================== */
.view-panel { min-width: 0; }
.view-panel[hidden] { display: none; }


/* ==========================================================================
   Phone compaction — calendar toolbar and filter bar (≤680px).
   Last in the file on purpose: these reflow rules must outrank the component
   defaults above at equal specificity.
   ========================================================================== */
@media (max-width: 680px) {
  /* THE TOOLBAR WAS A TOWER. Every control wrapped to its own line — nav row,
     title row, dispo pill row, count row, Filtres row — ~230px of chrome
     before the first date. Three tight rows instead: [nav … Filtres],
     [title], [dispo … count]. */
  .cal-toolbar { padding: var(--space-5) var(--space-7) var(--space-3); row-gap: var(--space-3); }
  /* The spacer goes back to being a spacer (the 680px rule above turns it
     into a row break; here the break comes from the title's own 100% basis). */
  .cal-toolbar .header-spacer { flex: 1 1 auto; height: auto; order: 2; }
  .cal-nav { order: 1; }
  #filters-toggle { order: 3; }
  .cal-title { order: 4; flex: 1 0 100%; font-size: 14px; }
  .cal-avail { order: 5; padding-block: 2px; }
  .result-count { order: 6; margin-left: auto; }

  /* THE FILTER BAR SPRAWLED OVER SIX RAGGED ROWS. Two single-line rows now:
     the act chips, then statut + montant + tri together — each row scrolls
     sideways instead of wrapping, bled to the card edge so the scroll reaches
     the viewport like the calendar grid does. */
  .filterbar { padding: var(--space-5) var(--space-7); gap: var(--space-4); }
  .filterbar > .chip-group, .filterbar-row {
    flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    margin-inline: calc(-1 * var(--space-7)); padding-inline: var(--space-7);
  }
  .filterbar > .chip-group::-webkit-scrollbar, .filterbar-row::-webkit-scrollbar { display: none; }
  /* Nothing inside a scroll row may shrink or wrap — the row scrolls instead. */
  .filterbar .chip, .filterbar .seg, .filterbar .seg-btn, .filterbar-row .btn { flex: none; }
  .filterbar-row { gap: var(--space-4); }
  /* The nested montant group rides the row's scroll — one scroll container. */
  .filterbar-row .chip-group { flex-wrap: nowrap; margin-inline: 0; padding-inline: 0; }
  /* A flexible spacer is meaningless inside a scroll row. */
  .filterbar-row .header-spacer { display: none; }
}

/* Ambient mark drift — the Nota logo, twenty-four times, adrift far behind the
   site content (app.js driftBuild deals each copy its place and tempo). One
   fixed site-wide layer (#site-bg) rides behind ALL panes — no band boundary
   ever slices a mark again. The arrival chooser stays clear; the gate's
   animated aura supplies motion without a second field of cubes. */
.mark-drift { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
/* Behind everything, edge to edge, and it arrives smoothly — a slow fade-in
   so the scene breathes into place instead of popping. */
.mark-drift--site { display: block; opacity: .25; }
@keyframes mark-fade { from { opacity: 0; } to { opacity: 1; } }
/* Two clocks per mark, both endless and seamless: the wrapper wanders a
   closed loop through two waypoints (out, across, home — never retracing
   itself) while the mark itself tumbles like a thrown die — one full, even
   turn around its own random 3D axis (linear — a roll has no resting point
   to ease toward). Splitting them keeps both loops smooth. Depth (app.js:
   one draw per mark) sets the size, the weight (--o), the softness (--blur)
   and how far it roams — near marks glide boldly in front of small,
   blurred, barely-stirring distant ones: parallax from a single random
   number. */
.mark-drift i {
  position: absolute; left: var(--x); top: var(--y);
  width: var(--s); height: var(--s);
  /* Half the die's edge — every face folds out to this depth. */
  --h: calc(var(--s) / 2);
  opacity: var(--o, 0.025);
  filter: blur(var(--blur, 0px));
  /* The stage depth that turns the tumble from a flat spin into a die
     rolling toward and away from the eye. */
  perspective: 400px;
  animation: mark-wander var(--d) ease-in-out var(--dl) infinite;
}
/* The die's body: six faces folded into a cube, tumbling as one. Hidden
   backfaces keep it reading as a solid object, not layered glass. */
.mark-drift .cube {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  animation: mark-tumble var(--sd) linear var(--dl) infinite;
}
.mark-drift .cube svg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  backface-visibility: hidden;
}
.mark-drift .cube svg:nth-child(1) { transform: translateZ(var(--h)); }
.mark-drift .cube svg:nth-child(2) { transform: rotateY(180deg) translateZ(var(--h)); }
.mark-drift .cube svg:nth-child(3) { transform: rotateY(90deg) translateZ(var(--h)); }
.mark-drift .cube svg:nth-child(4) { transform: rotateY(-90deg) translateZ(var(--h)); }
.mark-drift .cube svg:nth-child(5) { transform: rotateX(90deg) translateZ(var(--h)); }
.mark-drift .cube svg:nth-child(6) { transform: rotateX(-90deg) translateZ(var(--h)); }
@keyframes mark-wander {
  0%, 100% { transform: translate(0, 0); }
  33% { transform: translate(var(--dx1), var(--dy1)); }
  66% { transform: translate(var(--dx2), var(--dy2)); }
}
@keyframes mark-tumble {
  from { transform: rotate3d(var(--ax), var(--ay), var(--az), 0); }
  to { transform: rotate3d(var(--ax), var(--ay), var(--az), var(--spin)); }
}
@media (prefers-reduced-motion: reduce) { .mark-drift i, .mark-drift .cube { animation: none; } }

/* ==========================================================================
   Conformité (ADR 0033 §5 · ADR 0031) — the notary landing's compliance block.
   Detailed articles stay under the sign-in gate, outside the short film.
   Folds away with the gate: signed in, the console is a workspace.
   ========================================================================== */
.nc-conformite { margin-top: var(--space-16); padding-top: var(--space-12); border-top: 1px solid var(--border); }
/* Signed in, the console is a workspace and the compliance band folds away
   with the gate. The band is no longer the form's next sibling (it sits in the
   pane's grid, one level up), so the fold reads the gate through the wrap. */
.nc-conformite-kicker { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--subtitle-ink); margin-bottom: var(--space-3); }
.nc-conformite-h { font-size: var(--type-h4); line-height: var(--type-h4-lh); letter-spacing: var(--type-h4-ls); color: var(--subtitle-ink); margin: 0 0 var(--space-5); }
.nc-conformite-tiles { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-4); }
.nc-conformite-tile {
  display: grid; grid-template-columns: auto 1fr; column-gap: var(--space-5); row-gap: var(--space-1); align-items: start;
  padding: var(--space-5) var(--space-6);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
}
.nc-conformite-ic {
  grid-row: 1 / span 2; width: 30px; height: 30px; border-radius: var(--radius-sm);
  display: grid; place-items: center; color: var(--brand); background: var(--brand-tint);
}
.nc-conformite-ic svg { width: 18px; height: 18px; }
.nc-conformite-art { font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--subtitle-ink); }
.nc-conformite-txt { font-size: 13px; line-height: 1.45; color: var(--ink); }
.nc-conformite-order { margin: var(--space-5) 0 0; font-size: 12.5px; font-weight: 700; color: var(--ink-muted); }
.nc-conformite-link { display: inline-block; margin-top: var(--space-3); font-size: 13px; font-weight: 700; color: var(--brand); }

/* ==========================================================================
   Les promesses du notaire (ADR 0052 §A) — le bloc qui dit, avant le compte,
   ce que Nota donne : l'agenda, les trous comblés, ce que l'urgence paie, la
   fiche complète. Même registre que la bande Conformité plus bas (kicker,
   sur-titre, tuiles carrées sur --surface) : deux blocs d'annonce, un seul
   dessin. Le titre d'une tuile est de l'encre, jamais du bleu (registre
   d'encre) ; le bleu ne porte ici que le glyphe et le MONTANT.
   ========================================================================== */
/* Signé, la console est un plan de travail : le bloc se replie avec la porte,
   exactement comme #nc-conformite (il lit la porte à travers le wrap). */
/* Quatre promesses veulent un carré 2×2, jamais trois et une orpheline : un
   auto-fit donnait 3 + 1 dès que le rail passait 900px (constaté au
   navigateur, 2026-09-12). Deux colonnes fixes dès qu'il y a la place. */
/* Le chiffre de l'urgence : la seule chose bleue de la tuile, parce que c'est
   un montant. Vide tant que app.js ne l'a pas écrit — la phrase qui suit se
   tient seule, elle ne commence pas par une espace orpheline. */
/* Le chiffre de l'urgence ouvre la phrase, en encre : c'est une PHRASE, pas un
   montant isolé, et le registre d'encre réserve le bleu à une information qui
   se montre seule (un montant, un lien, une pastille). Une phrase entière en
   bleu se lisait comme un lien. */

/* ==========================================================================
   Live support chat (ADR 0026 · ADR 0033 §5) — the floating question door.
   Its own `sup-*` namespace: the retained-act `.chat-*` rules (a flex column,
   start-aligned) once reached in and dropped the visitor's bubbles on the
   wrong side. Same square scale as every control; brand blue only on the
   trigger and the visitor's own bubbles. Fixed above everything, footer
   included — and STACKED above the guide « ? » bubble on desktop: bottom
   70px clears the bubble's 16px + 42px (ux-nav.test.mjs pins the sum).
   Phones drop the fab (the drawer's « Messagerie » row opens the panel),
   so the calendar corner ADR 0022 cleared stays clear.
   ========================================================================== */
.sup-wrap { position: fixed; right: 16px; bottom: 70px; z-index: 60; display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }
.sup-fab {
  appearance: none; font: inherit; border: 1px solid var(--brand); cursor: pointer; position: relative;
  width: 48px; height: 48px; border-radius: var(--radius);
  background: var(--surface); color: var(--brand); box-shadow: var(--shadow);
  display: inline-flex; align-items: center; justify-content: center;
}
.sup-fab:hover { background: var(--action-tint); border-color: var(--action-ink); color: var(--action-ink); box-shadow: var(--shadow-lg); }
.sup-fab:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 2px; }
/* The unread mark — the one round thing here: an 8px dot, as the register allows. */
.sup-fab-dot { position: absolute; top: 6px; right: 6px; width: 8px; height: 8px; border-radius: 50%; background: var(--danger); box-shadow: 0 0 0 2px var(--brand); }
.sup-panel {
  width: min(380px, calc(100vw - 32px));
  max-height: calc(100dvh - 28px); overflow-y: auto;
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); overflow-x: hidden; overflow-y: auto;
}
.sup-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); padding: var(--space-6) var(--space-6) var(--space-5) var(--space-8); border-bottom: 1px solid var(--border); }
.sup-title { font-weight: 800; letter-spacing: -0.01em; }
.sup-sub { margin: 2px 0 0; font-size: 12.5px; line-height: 1.4; color: var(--ink-muted); max-width: 30ch; }
/* La fermeture est une icône carrée du registre, pas un caractère posé dans le
   texte : même gabarit que les autres boutons-icônes, et une cible de 28 px. */
.sup-close {
  appearance: none; border: 1px solid var(--border); background: transparent; color: var(--ink-muted);
  font: inherit; font-size: 14px; line-height: 1; cursor: pointer; flex: none;
  width: 28px; height: 28px; display: inline-grid; place-items: center; border-radius: var(--radius-sm);
}
.sup-close:hover { background: transparent; border-color: var(--action-ink); color: var(--ink); }
.sup-close:focus-visible { outline: 2px solid var(--action-ink); outline-offset: 1px; }
/* ADR 0046 — le journal ne réserve plus 96 px de vide. Un fil neuf n'a rien à
   montrer : ce sont les questions d'amorce, juste dessous, qui occupent la
   place, et elles, elles mènent quelque part. Le journal ne prend donc de la
   hauteur qu'une fois qu'il porte des bulles. */
.sup-log { max-height: 300px; overflow-y: auto; padding: var(--space-7) var(--space-8); display: flex; flex-direction: column; justify-content: flex-end; gap: var(--space-5); }
.sup-log:empty { padding: 0; }
.sup-log-op { min-height: 80px; max-height: 240px; border: 1px solid var(--border); border-radius: var(--radius); margin-bottom: 10px; }
.sup-empty { font-size: 13px; line-height: 1.5; color: var(--ink-muted); }
/* A message is a column — the bubble, then its « who · when » line — on the
   end side for the reader's own, the start side for the other. */
.sup-msg { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; }
.sup-msg.is-mine { align-items: flex-end; }
.sup-bubble {
  max-width: 85%; padding: 7px 10px; font-size: 13.5px; line-height: 1.4;
  border-radius: var(--radius); white-space: pre-wrap; word-break: break-word;
  background: var(--surface-inset); color: var(--ink); border: 1px solid var(--border);
}
.sup-msg.is-mine .sup-bubble { background: var(--brand); color: var(--brand-ink); border-color: transparent; }
/* L'assistant a SA bulle : le même registre que celle de Nota, avec un filet
   de marque à gauche qui dit d'un coup d'œil que c'est la machine qui a
   répondu — jamais un déguisement en personne. */
.sup-msg[data-de='assistant'] .sup-bubble { border-left: 2px solid var(--brand); }
/* « L'assistant écrit… » : trois points qui respirent, du côté de l'assistant.
   La bulle garde la hauteur d'une ligne pour que le fil ne saute pas quand la
   vraie réponse la remplace. */
.sup-bubble-typing { display: inline-flex; align-items: center; gap: 4px; min-height: 20px; }
.sup-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--ink-muted); opacity: 0.35; animation: sup-pulse 1.2s ease-in-out infinite; }
.sup-dot:nth-child(2) { animation-delay: 0.15s; }
.sup-dot:nth-child(3) { animation-delay: 0.3s; }
@keyframes sup-pulse { 0%, 60%, 100% { opacity: 0.25; } 30% { opacity: 0.9; } }
@media (prefers-reduced-motion: reduce) { .sup-dot { animation: none; opacity: 0.5; } }
/* Les questions d'amorce — des cibles, pas de la décoration : elles occupent
   le vide qu'ouvrait le journal et disent ce que l'assistant sait traiter. */
.sup-suggest { display: flex; flex-wrap: wrap; gap: var(--space-3); padding: var(--space-6) var(--space-8) 0; }
.sup-chip {
  appearance: none; cursor: pointer; font: inherit; font-size: 12.5px; line-height: 1.3;
  padding: var(--space-4) var(--space-5); border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: var(--surface-inset); color: var(--ink);
}
.sup-chip:hover { border-color: var(--border-strong); background: var(--surface); }
.sup-chip:focus-visible { outline: 2px solid var(--action-ink); outline-offset: 1px; }
/* L'escalade se lit — même registre que « conversation terminée », en marque. */
.sup-escalade { margin: 0; padding: 8px 14px; font-size: 12.5px; line-height: 1.45; color: var(--ink-muted); border-top: 1px dashed var(--border); }
.sup-meta { display: flex; gap: var(--space-3); font-size: 11.5px; color: var(--ink-muted); padding: 0 2px; }
.sup-who { font-weight: 700; }
/* Un bloc, pas une liste de fiches : deux messages de suite du même côté se
   serrent, et la signature « qui · quand » ne se pose qu'au PIED du bloc —
   une conversation de six lignes cesse d'être six fois « Vous · 15:33 ». */
.sup-log .sup-msg.is-cont { margin-top: calc(var(--space-5) * -1 + var(--space-2)); }
.sup-msg.is-mid .sup-meta { display: none; }
.sup-ended { margin: 0; padding: 8px 14px; font-size: 12.5px; color: var(--ink-muted); border-top: 1px dashed var(--border); }
.sup-form { padding: var(--space-6) var(--space-8) var(--space-7); border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: var(--space-4); }
/* Le composeur est UN champ, pas deux boîtes côte à côte : la rangée porte le
   cadre et l'anneau de focus, le champ et le bouton vivent dedans. */
.sup-row {
  display: flex; align-items: flex-end; gap: var(--space-3);
  padding: var(--space-3) var(--space-3) var(--space-3) var(--space-5);
  border: 1px solid var(--border-strong); border-radius: var(--radius); background: var(--surface);
}
.sup-row:focus-within { border-color: var(--ring); box-shadow: 0 0 0 3px var(--focus-ring); }
/* Grows with the text (field-sizing where the browser has it, app.js
   otherwise), capped so the log keeps its room. */
.sup-text {
  flex: 1; resize: none; min-height: 26px; max-height: 160px; overflow-y: auto; field-sizing: content;
  min-width: 0; padding: var(--space-3) 0; border: 0; border-radius: 0; background: transparent;
}
.sup-text:focus { border: 0; outline: none; box-shadow: none; }
.sup-send { flex: none; padding: var(--space-4) var(--space-6); font-size: 13px; }
.sup-count { margin: 0; min-height: 1.5em; font-size: 12px; color: var(--ink-muted); text-align: right; font-variant-numeric: tabular-nums; }
.sup-error { margin: 0; font-size: 13px; color: var(--danger); }
/* La porte du courriel : un lien discret tant qu'il ne sert pas. Elle ne prend
   qu'une ligne, et le champ n'apparaît qu'une fois ouverte. */
.sup-mail-open {
  appearance: none; border: 0; background: transparent; padding: 0; font: inherit;
  font-size: 12px; color: var(--ink-muted); text-align: left; cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px; align-self: flex-start;
}
.sup-mail-open:hover { color: var(--ink); }
.sup-mail-open:focus-visible { outline: 2px solid var(--action-ink); outline-offset: 2px; border-radius: var(--radius-xs); }
.sup-mail-open[aria-expanded='true'] { display: none; }
/* The optional courriel, one line under the composer: label · field, help beneath. */
.sup-courriel-row { display: flex; flex-direction: column; gap: var(--space-2); }
.sup-courriel-lbl { font-size: 12px; font-weight: 600; color: var(--ink-muted); }
.sup-opt { font-weight: 500; }
.sup-courriel { width: 100%; min-width: 0; padding: var(--space-4) var(--space-5); font-size: 13px; }
.sup-courriel-help { margin: 0; font-size: 12px; }
.sup-reply-courriel { margin: 0 0 8px; min-height: 1.5em; }
#chat-reply-error, #chat-reply-sent { min-height: 1.5em; }
#chat-reply-dialog textarea { width: 100%; resize: vertical; }
@media (max-width: 767.98px) {
  /* The guide « ? » left phones (ADR 0022) so the calendar owns its corner —
     the chat fab must not take its place. The panel still opens from the
     drawer's « Messagerie » row and from an emailed #messagerie link. */
  .sup-fab { display: none; }
  .sup-wrap { right: 10px; bottom: 10px; left: 10px; align-items: flex-end; }
  .sup-panel { width: 100%; }
}

/* --- Les documents de la conversation (ADR 0032) --------------------------
   Sous le fil, au même endroit des deux côtés : ce que l'un envoie, l'autre le
   lit là. Aucune couleur d'accent — un document n'est ni une alerte ni une
   récompense, c'est une pièce du dossier. L'état de l'envoi se dit en mots
   (aria-live), parce qu'une barre de progression sans phrase ne dit pas ce qui
   se passe quand elle s'arrête. */
.chat-docs { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border); }
.chat-doc-count { margin-bottom: 8px; }
.chat-doc-list { list-style: none; margin: 0 0 8px; padding: 0; display: grid; gap: 4px; }
.chat-doc { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; font-size: 13px; }
.chat-doc-open {
  font: inherit; padding: 0; border: 0; background: none; color: var(--brand);
  text-decoration: underline; cursor: pointer; text-align: left;
}
.chat-doc-open:hover { text-decoration: none; }
.chat-doc-meta { color: var(--ink-muted); font-size: 11.5px; }
.chat-doc-vide { color: var(--ink-muted); font-size: 12.5px; }
.chat-doc-input { display: none; }
.chat-doc-etat { margin: 6px 0 0; font-size: 12px; color: var(--ink-muted); min-height: 1em; }
.chat-doc-etat[data-etat="erreur"] { color: var(--danger); }
/* The act's checklist inside the document block (ADR 0032 × audit 2.1): one
   row per expected piece, its own Joindre, marked sent once confirmed. */
.chat-doc-checklist { list-style: none; margin: 0 0 8px; padding: 0; display: grid; gap: 6px; }
.chat-doc-item { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13px; }
.chat-doc-item-name { font-weight: 600; }
.chat-doc-item[data-sent='true'] .chat-doc-item-name::before { content: '✓ '; color: var(--ok); }
.chat-doc-item .chat-doc-etat { margin: 0; flex-basis: 100%; }
.chat-doc-free { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 13px; margin-top: 4px; }
.chat-doc-free-lbl { color: var(--ink-muted); }
/* Back from Stripe (audit 2.2): the success card the redirect skipped. */
.checkout-success { margin-top: 10px; padding: 12px 16px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.checkout-success-h { font-weight: 700; font-size: 14px; display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: baseline; }
.checkout-success-h .money { color: var(--brand); }
.checkout-success .dossier-next { margin-top: 10px; }
.checkout-success .actions-inline { margin-top: 10px; }

/* =============================================================================
   Print. Paper is white: the light canvas tokens are restated for the dark
   theme and the system-dark media block (both outrank :root), the fixed
   chrome goes — header, drawer, bubbles, backdrop dice, footer nav, gate,
   dialogs — and the active pane keeps its content. The demo banner STAYS: a
   printed fictional carnet must still say so. Only canvas tokens are
   restated; the brand ramp is shared, everything else follows.
   ========================================================================== */
@media print {
  :root, :root[data-theme='dark'], :root:not([data-theme='light']) {
    color-scheme: light;
    --brand: var(--nota-blue-700); --brand-bright: var(--nota-blue-500); --brand-ink: var(--paper); --brand-hover: var(--nota-blue-800);
    --brand-on-surface: var(--brand); /* sur papier, l'état reprend la marque elle-même */
    --brand-word-ink: var(--ink);
    --bg: var(--paper); --surface: var(--paper); --surface-inset: var(--nota-blue-50); --surface-hover: var(--canvas-surface-hover);
    --ink: var(--nota-blue-950); --ink-muted: var(--canvas-ink-muted); --border: var(--canvas-border); --border-strong: var(--canvas-border-strong); --ring: var(--nota-blue-600);
    --subtitle-ink: var(--canvas-subtitle-ink);
    --shadow-sm: none; --shadow: none; --shadow-lg: none; --shadow-brand: none;
  }
  .site-header, .site-footer nav, .guide-fab, .sup-wrap, .mark-drift, .mnav, .mnav-scrim,
  .toast, .skip, .nav-burger, dialog { display: none !important; }
  body { background: var(--bg); color: var(--ink); }
  * { box-shadow: none !important; text-shadow: none !important; -webkit-backdrop-filter: none !important; backdrop-filter: none !important; }
  .wrap { max-width: none; padding: 0; }
  .tab-pane[hidden] { display: none !important; }
}

/* ADR 0041 — l'acte annulé par le client, en attente de la décision du notaire
   sur l'indemnité : une carte à part, sans client ni fil, avec sa réclamation. */
.pill-annulee { background: transparent; color: var(--ink-muted); border: 1px solid var(--border); }
.nc-card.is-annulee { border-style: dashed; }
.nc-indemnite { margin-top: 10px; padding-top: 8px; border-top: 1px dashed var(--border); }
.nc-indemnite-form { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.nc-indemnite-amt { max-width: 160px; }
.nc-indemnite-just { resize: vertical; min-height: 56px; }
.nc-indemnite-err { color: var(--danger, var(--ink)); }
.devis-annulation { margin: 6px 0 0; }

.coverage-note { grid-column: 1 / -1; padding: 1rem; border: 1px solid currentColor; border-radius: var(--radius); max-width: 100%; }
.coverage-note .help { margin: 0 0 .75rem; }

/* Email preferences use the same surface and controls as the profile. */
#email-preferences-dialog {
  width: min(640px, calc(100vw - 32px));
  max-height: calc(100dvh - 48px);
  overflow-y: auto;
  padding: 24px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  color: var(--ink);
}
#email-preferences-dialog .check-row { display: flex; align-items: center; gap: 12px; min-height: 44px; }
#email-preferences-dialog input { width: 18px; height: 18px; accent-color: var(--brand); }
#email-preferences-dialog button { margin-block: 12px; }

/* Final booking step: keep the contact form readable on wide screens. */
.day-book[data-at='4'] {
  width: 100%; max-width: 1120px; margin-inline: auto; box-sizing: border-box;
  gap: 20px;
}
.day-book[data-at='4'] #o-where-step { padding: 20px; }
.day-book[data-at='4'] #prefix-row { margin-bottom: 0; }
.day-book[data-at='4'] #prefix-row > .coverage-note { grid-column: 1 / -1; }
.day-book[data-at='4'] .book-identity {
  margin-top: 0; padding-top: 20px;
  grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px;
}
.day-book[data-at='4'] .book-identity .form-row { min-width: 0; }
.day-book[data-at='4'] .book-identity .form-row:has(#o-sms) { grid-column: 1 / -1; }
.day-book[data-at='4'] .book-identity .form-row:has(#o-sms) .check-line { align-items: flex-start; max-width: 760px; }
.day-book[data-at='4'] #identity-rows input { width: 100%; max-width: none; box-sizing: border-box; }
.day-book[data-at='4'] .book-identity .help { font-size: 13px; line-height: 1.5; }
.day-book[data-at='4'] .offer-hint { margin: 0; }
.day-book[data-at='4'] .consent-line { margin: 0; font-size: 12px; line-height: 1.5; }
.day-book[data-at='4'] .book-nav { margin-top: 4px; }
@media (max-width: 760px) {
  .day-book[data-at='4'] .book-identity { grid-template-columns: minmax(0, 1fr); }
  .day-book[data-at='4'] #o-where-step { padding: 16px; }
}
/* Inactive validation messages must not reserve a flex row or its gap. */
.day-book[data-at] > [data-screen][hidden] { display: none !important; }

/* One tour surface for both account roles; native dialog contains keyboard focus. */
.account-tour {
  position: fixed; inset: auto 20px 20px auto; margin: 0;
  width: min(460px, calc(100vw - 32px)); max-height: min(50dvh, 420px);
  box-sizing: border-box; overflow: auto; padding: 24px;
  color: var(--ink); background: transparent; border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: none;
}
.account-tour[open] { animation: account-tour-in var(--motion-fast) var(--ease-ui); }
/* No scoped ::backdrop — the shared dialog::backdrop owns the scrim. */
.account-tour h2 { margin: 10px 0; }
.account-tour p { margin: 0 0 20px; line-height: 1.6; }
.account-tour-progress { color: var(--brand); font-size: 12px; font-weight: 700; }
.account-tour-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
.account-tour-actions .btn { min-height: 44px; }
.account-tour-actions .btn:first-child { margin-right: auto; }
.account-tour-target { outline: 3px solid var(--brand); outline-offset: 5px; scroll-margin-top: 110px; }
.account-tour-replay { justify-self: start; margin-bottom: 16px; }
@keyframes account-tour-in { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } }
@media (max-width: 560px) { .account-tour { inset: auto 16px 16px; padding: 18px; } }
@media (prefers-reduced-motion: reduce) { .account-tour[open] { animation: none; } }
.account-tour h2 { animation: account-tour-in var(--motion-ui) var(--ease-ui); }
@media (prefers-reduced-motion: reduce) { .account-tour h2 { animation: none; } }

/* The client guide follows the live form and leaves every control usable. */
.client-walk {
  position: fixed; z-index: 90; right: 20px; bottom: 20px;
  width: min(360px, calc(100vw - 32px)); box-sizing: border-box;
  max-height: calc(100dvh - 96px); overflow-y: auto; overscroll-behavior: contain;
  padding: 12px 16px 16px; border: 1px solid var(--border-strong);
  border-radius: var(--radius); background: var(--surface); color: var(--ink);
  box-shadow: var(--shadow-lg);
}
.client-walk-top { display: flex; position: sticky; top: -12px; z-index: 2; align-items: center; justify-content: space-between; gap: 8px; background: var(--surface); }
.client-walk-progress { color: var(--brand-on-surface); font-size: 12px; font-weight: 700; }
.client-walk-skip, .client-walk-toggle, .client-walk-link {
  border: 0; background: transparent; color: var(--ink-muted); cursor: pointer;
  font: inherit; font-size: 13px; min-height: 44px; padding: 4px 8px;
}
.client-walk-skip { text-decoration: underline; }
.client-walk-toggle, .client-walk-link { color: var(--brand-on-surface); font-weight: 600; }
.client-walk button:focus-visible, .client-walk summary:focus-visible { outline: 2px solid var(--action-ink); outline-offset: 2px; }
.client-walk h2 { font-size: var(--type-h3); line-height: var(--type-h3-lh); margin: 4px 0 8px; animation: clientWalkTitleIn var(--motion-ui) var(--ease-ui) both; }
.client-walk p { font-size: 14px; line-height: 1.5; margin: 0 0 12px; animation: clientWalkCopyIn var(--motion-ui) var(--ease-ui) 40ms both; }
@keyframes clientWalkTitleIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@keyframes clientWalkCopyIn { from { opacity: 0; transform: translateY(-2px); } to { opacity: 1; transform: none; } }
.client-walk .btn { min-height: 44px; }
.client-walk-actions { display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: center; }
.client-walk-actions .btn { flex: 1; }
.client-walk-date-field { display: grid; gap: 6px; margin: 0 0 12px; font-size: 13px; font-weight: 600; animation: clientWalkFieldIn var(--motion-ui) var(--ease-ui) 80ms both; }
@keyframes clientWalkFieldIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.client-walk-date-field input {
  width: 100%; min-width: 0; min-height: 44px; box-sizing: border-box;
  font: inherit; padding: 10px 40px 10px 12px;
  border: 2px solid var(--border); border-radius: var(--radius);
  background: var(--surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'/%3E%3Cline x1='16' y1='2' x2='16' y2='6'/%3E%3Cline x1='8' y1='2' x2='8' y2='6'/%3E%3Cline x1='3' y1='10' x2='21' y2='10'/%3E%3C/svg%3E") no-repeat right 12px center;
  color: var(--ink);
  transition: border-color var(--motion-fast), box-shadow var(--motion-fast), transform var(--motion-fast);
}
.client-walk-date-field input:hover { border-color: var(--border-strong); }
.client-walk-date-field input:focus { border-color: var(--action-ink); box-shadow: 0 0 0 3px var(--ring); outline: none; }
.client-walk-date-field input:focus-visible { border-color: var(--action-ink); box-shadow: 0 0 0 3px var(--ring); outline: none; }
.client-walk-date-field input:invalid { border-color: var(--danger); }
.client-walk-date-field input::-webkit-calendar-picker-indicator { opacity: 0; width: 100%; height: 100%; position: absolute; right: 0; top: 0; cursor: pointer; }
.client-walk-body[hidden], .client-walk-date-field[hidden], .client-walk-link[hidden] { display: none; }
.client-walk.is-minimized {
  width: min(360px, calc(100vw - 32px));
  max-width: calc(100vw - 32px);
  padding-block: 4px;
}
.client-walk.is-minimized .client-walk-top { position: static; gap: 8px; min-width: 0; }
.client-walk.is-minimized .client-walk-progress {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.client-walk.is-minimized .client-walk-toggle { white-space: nowrap; flex: none; }
.client-walk-target { outline: 2px solid var(--brand); outline-offset: 4px; scroll-margin-block: 280px 40px; }
#cal-grid .client-walk-target { scroll-margin-block: 90px 360px; }
#day-dialog > .client-walk {
  position: sticky; top: 0; bottom: auto; right: auto; z-index: 6;
  width: auto; margin: 0 20px 12px; padding: 4px 16px 12px; max-height: min(360px, 58dvh);
}
#day-dialog > .client-walk.is-minimized { padding-block: 4px; }
#day-dialog:has(> .client-walk) .day-head { position: relative; }
#day-dialog > .client-walk h2 { margin-bottom: 4px; }
#day-dialog > .client-walk p { margin-bottom: 10px; }
.client-walk-animation { margin-top: 10px; border-top: 1px solid var(--border); }
.client-walk-animation > summary { min-height: 44px; box-sizing: border-box; padding-block: 12px; font-size: 13px; cursor: pointer; color: var(--brand-on-surface); }
@media (prefers-reduced-motion: reduce) {
  .client-walk h2, .client-walk p, .client-walk-date-field { animation: none; }
}
@media (max-width: 560px) {
  .client-walk { right: 16px; bottom: max(16px, env(safe-area-inset-bottom)); }
  #day-dialog > .client-walk { margin-inline: 12px; }
}

/* Shared help affordance: visible hit area, readable copy, both themes. */
.itip { vertical-align: middle; margin-left: 8px; }
.itip-btn {
  width: 32px; height: 32px; min-height: 32px; padding: 0;
  border: 1px solid var(--border-strong); border-radius: 50%;
  background: var(--surface-inset); color: var(--brand);
}
.itip-btn svg { width: 18px; height: 18px; }
.itip-btn::after { inset: 0; }
.itip-btn:hover, .itip[data-open='true'] .itip-btn {
  color: var(--action-ink); border-color: currentColor; background: var(--action-tint);
}
.itip[data-tone='warn'] .itip-btn { color: var(--warn); }
.itip-pop {
  box-sizing: border-box; width: 360px; max-width: calc(100vw - 32px);
  padding: 16px 18px; font-size: 14px; line-height: 1.6; font-weight: 400;
  border-radius: var(--radius); overflow-y: auto; overflow-wrap: anywhere;
  pointer-events: auto;
}
.itip[data-dismissed='true'] > .itip-pop { display: none; }
@media (pointer: coarse) {
  .itip-btn { width: 44px; height: 44px; min-height: 44px; }
}

/* Profile fields share an input baseline; supporting text sits below it. */
.profil-fields { align-items: start; gap: 20px; }
.profil-fields .form-row { min-width: 0; }
.profil-fields .help { margin: 6px 0 0; font-size: 13px; line-height: 1.5; }
@media (max-width: 860px) {
  /* An offer summary and its detail row form one card, never adjacent cards. */
  .my-offers tbody { grid-template-columns: minmax(0, 1fr); }
  .my-offers .c-acte, .my-offers .c-date, .my-offers .c-montant, .my-offers .c-statut {
    width: auto; min-width: 0;
  }
  .my-offers .c-statut { justify-self: stretch; }
  .my-offers .my-offer-status { display: inline-block; max-width: 100%; box-sizing: border-box; }
}

/* Shared questionnaire cards, including the dossier and optional details. */
#day-dialog:has(.day-book[data-at='2']) { width: min(96vw, 1040px); max-width: 1040px; }
.day-book[data-at='2'] { padding: 20px; gap: 16px; }
.day-book[data-at='2'] .book-rail { margin-bottom: 4px; }
.o-criteria .crit-sec { padding: 16px; gap: 16px; background: var(--surface); }
.o-criteria .crit-sec-h {
  margin: -16px -16px 0; padding: 14px 16px;
  gap: 8px 12px;
}
.o-criteria .crit-sec-grid { gap: 12px; }
.o-criteria .crit-sec-grid > .crit-row {
  padding: 12px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-inset); min-width: 0;
}
.o-criteria .crit-head { margin-bottom: 8px; }
/* Le « $ » entre DANS le champ (2026-09-12) : posé à côté, il repoussait le
   cadre du montant de dix pixels vers l'intérieur — deux champs l'un sous
   l'autre, « Montant du nouveau prêt » et « Prêteur hypothécaire », ne
   finissaient donc pas sur la même verticale. Le champ va jusqu'au rail, comme
   la liste, et l'unité se lit dans sa marge droite. */
.o-criteria .crit-unit-wrap { display: flex; position: relative; width: 100%; }
.o-criteria .crit-unit-wrap input[type='number'] { width: 100%; max-width: none; min-width: 0; padding-right: 28px; }
.o-criteria .crit-unit-wrap > .crit-unit {
  position: absolute; top: 0; right: 12px; height: 100%;
  display: inline-flex; align-items: center; pointer-events: none;
}
.o-criteria .crit-row .nselect { width: 100%; max-width: none; }
.o-criteria .crit-sec-grid > .crit-row .seg-btn { flex: 1 1 0; max-width: none; min-height: 44px; }
.o-criteria .crit-row .seg.seg-stack .seg-btn { flex: auto; }
#day-dialog .o-criteria .crit-row .seg.seg-stack .seg-btn { flex: 0 1 auto; }
.o-criteria .crit-more { margin-top: 0; }
.o-criteria .crit-sec[data-fold='true'] { padding-bottom: 0; gap: 0; }
@media (max-width: 600px) {
  #day-dialog:has(.day-book[data-at='2']) { width: 100%; max-width: 100%; }
  .day-book[data-at='2'] { padding: 14px; }
  .dossier-pricing .o-criteria .crit-sec-grid { grid-template-columns: minmax(0, 1fr); }
  .dossier-pricing .o-criteria .crit-sec-grid > .crit-row { grid-column: 1 / -1; grid-row: auto; }
}
/* The form's usable width, rather than the window, decides whether its
   compact loan fields can share a row. Long answer choices use the full
   section so their price rail cannot squeeze labels into vertical letters. */
@container book (width >= 520px) {
  #o-criteria > .crit-sec[data-groupe='pret'] > .crit-sec-grid > .crit-row[data-crit='valeur_pret'] { grid-column: 1; grid-row: 1; }
  #o-criteria > .crit-sec[data-groupe='pret'] > .crit-sec-grid > .crit-row[data-crit='preteur'] { grid-column: 2; grid-row: 1; }
  #o-criteria > .crit-sec[data-groupe='pret'] > .crit-sec-grid > .crit-row[data-crit='contexte'] { grid-column: 1 / -1; grid-row: 2; }
  #o-criteria > .crit-sec[data-groupe='pret'] > .crit-sec-grid > .crit-row[data-crit='approbation_bancaire'] { grid-column: 1 / -1; grid-row: 3; }
}
@container book (width < 520px) {
  #o-criteria .crit-sec-grid { grid-template-columns: minmax(0, 1fr); }
  #o-criteria .crit-sec-grid > .crit-row { grid-column: 1 / -1; grid-row: auto; }
}
.o-criteria .crit-row .nselect { min-width: 100%; align-self: stretch; box-sizing: border-box; }

/* Additional text belongs below its choice, with the same usable width. */
.o-criteria .crit-row:has(> .crit-other) { flex-direction: column; flex-wrap: nowrap; gap: 8px; }
.o-criteria .crit-row:has(> .crit-other) > :is(.crit-head, .crit-effet, .nselect, .help, .crit-other) {
  flex: none; width: 100%; min-width: 0; box-sizing: border-box;
}
.o-criteria .crit-other input[type='text'] { width: 100%; max-width: none; box-sizing: border-box; }
/* The optional rows share the same question rails as their section's required
   rows. Keep the vertical separation, but do not add a second horizontal
   inset inside the disclosure. */
.o-criteria .crit-sec > .crit-more .crit-sec-grid { padding: var(--space-6) 0 0; }
/* UN SEUL RAIL POUR TOUTE LA SECTION (2026-09-12, retour du propriétaire :
   « a lot of fields in the form that are not aligned »). Le volet des
   précisions portait son propre cadre AUTOUR des rangs : sa bordure d'un pixel
   poussait chaque question facultative d'un pixel vers la droite et lui coupait
   un pixel à droite — deux questions de la même section ne commençaient donc
   pas sur la même verticale, et les deux colonnes de la grille intérieure
   tombaient à côté de celles du dessus. Le cadre passe sur la BARRE, qui
   devient une carte de la même famille que les questions ; le volet, lui, ne
   pèse plus rien dans la mise en page. */
.o-criteria .crit-sec > .crit-more { border: 0; border-radius: 0; background: none; }
.o-criteria .crit-more > summary {
  padding: 12px; min-height: 44px; box-sizing: border-box;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-inset);
}
.o-criteria .crit-more > summary:hover { border-color: var(--border-strong); }
.o-criteria .crit-sec-grid > .crit-row { margin: 0; }

/* Keep every questionnaire track inside its card. Without an explicit
   shrinkable width, a nested flex track can preserve its intrinsic content
   width at browser zoom and pull the right-hand choices away from the shared
   rail. */
.o-criteria .crit-sec-grid,
.o-criteria .crit-row,
.o-criteria .crit-dep,
.o-criteria .crit-dep .seg {
  width: 100%;
  max-width: 100%;
  min-width: 0;
  box-sizing: border-box;
}

/* Postal lookup: a compact input followed by a clear geographic result. */
#o-where-step .coverage-note { background: var(--surface-inset); border-color: var(--border); padding: 16px; }
#o-where-step .coverage-note[data-state='none'] { border-left: 3px solid var(--warn); }
#o-where-step .coverage-note[data-state='covered'] { border-left: 3px solid var(--brand); }
.coverage-summary { display: flex; align-items: center; gap: 16px; margin-bottom: 12px; }
.coverage-count { font-size: var(--type-h2); line-height: 1; color: var(--brand); font-variant-numeric: tabular-nums; }
.coverage-caption { display: grid; gap: 4px; min-width: 0; }
.coverage-caption > span { font-size: 13px; color: var(--ink-muted); }
#o-where-step #prefix-row { gap: 10px 16px; }

/* Equal-weight, nonblocking analytics choice. Token-driven so it follows
   both themes instead of forcing a white card onto a dark canvas. */
.analytics-consent { position: fixed; inset: auto 16px 16px; z-index: 10000; max-width: 680px; margin: auto; padding: 18px; background: var(--surface); color: var(--ink); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); }
.analytics-consent[hidden] { display: none; }
.analytics-consent p { margin: 0 0 12px; font-size: 14px; line-height: 1.5; }
.analytics-consent button, #analytics-preferences:not(.footer-link) { font: inherit; cursor: pointer; padding: 8px 12px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--ink); margin-right: 8px; }
.analytics-consent button:hover, #analytics-preferences:not(.footer-link):hover { background: var(--action-tint); }

/* Help discovery remains available without crowding the conversation. */
.sup-topics { padding: 6px 14px; font-size: 12.5px; flex-shrink: 0; }
.sup-topics summary { cursor: pointer; color: var(--ink); padding: 8px 0; font-weight: 600; }
.sup-topics summary:focus-visible { outline: 2px solid var(--action-ink); outline-offset: 2px; }
.sup-topic-list { display: flex; flex-wrap: wrap; gap: 6px; max-height: 150px; overflow-y: auto; padding: 8px 2px; }
.sup-privacy { margin: 0; padding: 8px 14px; font-size: 12px; line-height: 1.4; color: var(--ink-muted); }

/* Search and delivery recovery stay inside the dependency-free messenger. */
.sup-topic-search { width: 100%; margin-top: 6px; min-height: 36px; }
.sup-topic-empty { margin: 6px 0; color: var(--ink-muted); }

/* --- Booking component consistency --------------------------------------
   One header pattern for every criterion: the label owns the left rail, the
   information affordance owns the top-right rail, and answer effects own a
   separate right rail. The question card itself is a surface, not another
   outlined box inside the outlined section. */
#day-dialog .o-criteria .crit-head,
#day-dialog .o-criteria .crit-text {
  position: relative;
  min-width: 0;
  min-height: 44px;
  padding-right: 52px;
  align-items: center;
}

#day-dialog .o-criteria .crit-head > .itip,
#day-dialog .o-criteria .crit-text > .itip,
#day-dialog .o-criteria .crit-sec-h > .itip {
  position: absolute;
  top: 0;
  right: 0;
  margin: 0;
  transform: none;
}

#day-dialog .o-criteria .crit-sec-h:has(> .itip) {
  position: relative;
  padding-right: 52px;
}

#day-dialog .o-criteria .crit-head > .crit-label,
#day-dialog .o-criteria .crit-text > .crit-label {
  min-width: 0;
  overflow-wrap: anywhere;
  line-height: 1.35;
}

#day-dialog .o-criteria .crit-req {
  max-width: 100%;
  margin-left: 8px;
  white-space: normal;
}

#day-dialog .o-criteria .crit-flag { align-items: center; }
#day-dialog .o-criteria .crit-flag input { margin-top: 0; }

/* Labels and prices are separate flex items. This keeps « Pas encore
   demandée » and « +200 $ » readable at every width. */
#day-dialog .o-criteria .crit-row .seg-btn {
  display: flex;
  flex: 1 1 180px;
  align-items: center;
  justify-content: flex-start;
  min-width: 0;
  min-height: 44px;
  line-height: 1.35;
  text-align: left;
  overflow-wrap: normal;
}

#day-dialog .o-criteria .crit-row .seg-btn .crit-add {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  margin-left: auto;
  padding-left: 12px;
  white-space: nowrap;
}

/* Keep controls readable without adding another visual frame around the
   question: the section is the grouping boundary, the surface is the row. */
#day-dialog .o-criteria .crit-sec-grid > .crit-row {
  border: 0;
  background: var(--surface);
}

#day-dialog .o-criteria .crit-sec {
  /* A confident blue wash separates each subsection from the white answer
     surfaces without adding another outline around the question. */
  background: color-mix(in srgb, var(--brand-bright) 20%, var(--surface));
}

/* Dans le dialogue, une question ne porte pas de cadre : la section est la
   frontière, la surface EST le rang. La barre des précisions suit ce registre
   — même surface, mêmes rails, aucun trait de plus — sinon elle se lisait
   comme un contrôle d'une autre famille, posé un pixel à côté des questions
   qu'elle ouvre. */
#day-dialog .o-criteria .crit-more > summary {
  border: 0;
  background: none;
}
#day-dialog .o-criteria .crit-more > summary:hover { color: var(--ink); }
#day-dialog .o-criteria .crit-more[open] > summary { margin-bottom: 0; }

/* Narrow forms keep each choice on its own row. Wider forms can share the
   space, with the minimum flex basis above preserving readable labels. */
@container book (width < 520px) {
  #day-dialog .o-criteria .crit-row .seg {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-3);
  }

  #day-dialog .o-criteria .crit-row .seg-btn {
    width: 100%;
    max-width: none;
    flex: 1 1 auto;
  }
}

/* Offer sections: the white parent is the deliberate separator. The tinted
   cards remain part of the Nota palette, but their spacing is now a real gap
   instead of blue meeting blue at a border. */
#day-dialog .book-step-offer,
#day-dialog .o-criteria {
  background: var(--surface);
}

#day-dialog .book-step-offer {
  gap: var(--space-12);
}

/* The offer step is intentionally allowed to remain a block in the base
   layout; use a sibling margin as well so the white separator survives that
   cascade and remains visible between each tinted section. */
#day-dialog .book-step-offer > .offer-sec + .offer-sec {
  margin-top: var(--space-12);
}

#day-dialog .o-criteria {
  gap: var(--space-12);
}

#day-dialog .offer-sec,
#day-dialog .o-criteria .crit-sec {
  background: var(--surface-inset);
}

#day-dialog .offer-sec .crit-sec-h,
#day-dialog .o-criteria .crit-sec-h {
  background: var(--surface);
}

/* Section pictograms are brand signals, not controls: no enclosing border or
   tint, including after the section is completed. */
#day-dialog .crit-sec-ic {
  border: 0;
  background: transparent;
  color: var(--brand);
  transition: color var(--motion-fast);
}

.sup-msg[data-delivery='unconfirmed'] .sup-bubble { border: 1px dashed var(--border-strong); }
.sup-delivery { color: var(--ink-muted); font-size: 12px; }
.sup-recover { font: inherit; font-size: 12px; padding: 6px 8px; color: var(--ink); background: var(--surface); border: 1px solid var(--border); cursor: pointer; }
.sup-recover:focus-visible { outline: 2px solid var(--action-ink); outline-offset: 2px; }
#chat-reply-recovery .help { white-space: pre-wrap; overflow-wrap: anywhere; }

/* ==========================================================================
   LA SALLE DE SIGNATURE — ADR 0047

   Plein écran, et volontairement sombre : une cérémonie n'est pas une page du
   site. Ce qui doit rester lisible à distance d'un écran — la chaîne
   d'authentification, l'état des quatre portes, le texte de conduite — l'est
   avant tout le reste. Le bandeau bêta est au-dessus de tout et ne se cache
   jamais.
   ========================================================================== */
.salle { position: fixed; inset: 0; z-index: 11000; display: flex; flex-direction: column; background: var(--nota-blue-950); color: var(--midnight-ink); }
.salle[hidden] { display: none; }
/* Le fond de la page ne défile plus derrière la salle. */
body.salle-ouverte { overflow: hidden; }

/* Le bandeau. Aucune règle ne le masque, aucun rendu ne le touche. */
.salle-beta { margin: 0; padding: 10px 16px; text-align: center; font-size: 13px; line-height: 1.45; background: var(--warn); color: var(--on-warn); }
.salle-beta strong { font-weight: 700; }

.salle-scene { flex: 1; display: grid; grid-template-columns: minmax(0, 1fr) 380px; min-height: 0; }

.salle-videos { position: relative; min-height: 0; background: var(--midnight-matte); }
.salle-video { display: block; width: 100%; height: 100%; object-fit: cover; background: var(--midnight-matte); }
.salle-video-distant { width: 100%; height: 100%; }
/* La vignette locale : assez grande pour se vérifier, assez petite pour ne pas
   voler l'attention de la personne d'en face. */
.salle-video-local { position: absolute; right: 16px; bottom: 16px; width: 22%; min-width: 140px; max-width: 260px; height: auto; aspect-ratio: 4 / 3; border: 1px solid var(--border-strong); border-radius: var(--radius); box-shadow: var(--shadow-lg); }

.salle-rail { display: flex; flex-direction: column; gap: 14px; padding: 18px; overflow-y: auto; background: var(--nota-blue-900); border-left: 1px solid var(--nota-blue-800); }
.salle-bloc { padding: 14px; background: var(--midnight-veil-soft); border: 1px solid var(--nota-blue-800); border-radius: var(--radius); }
.salle-etape-nom { margin: 0 0 8px; font-size: var(--type-h3); line-height: var(--type-h3-lh); letter-spacing: var(--type-h3-ls); }
.salle-etape-conduite { margin: 0 0 8px; font-size: 15px; line-height: 1.5; }
.salle-etape-constat { margin: 0; font-size: 13px; line-height: 1.45; color: var(--nota-blue-300); }

/* La chaîne d'authentification. C'est la ligne qu'on lit à voix haute : elle a
   droit à la plus grosse typographie de l'écran, en chasse fixe pour que S et 5
   ne se confondent pas. */
.salle-bloc-sas { text-align: center; }
.salle-sas-titre { margin: 0 0 6px; font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--midnight-ink); }
.salle-sas { margin: 0; font-family: var(--font-mono); font-size: var(--type-h2); font-weight: 700; letter-spacing: 0.12em; }
.salle-sas.is-confirme { color: var(--nota-blue-400); }
.salle-sas-aide { margin: 6px 0 0; font-size: 12px; line-height: 1.4; color: var(--nota-blue-300); }

.salle-portes-titre { margin: 0 0 8px; font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--midnight-ink); }
.salle-portes { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 8px; }
.salle-porte { display: grid; grid-template-columns: 20px minmax(0, 1fr); gap: 4px 8px; font-size: 14px; line-height: 1.4; }
.salle-porte-marque { color: var(--warn); font-weight: 700; }
.salle-porte.is-ouverte .salle-porte-marque { color: var(--nota-blue-400); }
.salle-porte-nom { font-weight: 600; }
/* Une porte fermée DIT pourquoi. Le motif s'aligne sous le nom, pas sous la
   marque : c'est une phrase, pas une puce. */
.salle-porte-motif { grid-column: 2; margin: 0; font-size: 13px; line-height: 1.4; color: var(--nota-blue-200); }

.salle-statut { display: flex; flex-direction: column; gap: 8px; }
.salle-statut-ligne { margin: 0; font-size: 13px; line-height: 1.45; color: var(--nota-blue-200); }
.salle-statut-ligne.is-alerte { padding: 10px; background: var(--danger-wash); border: 1px solid var(--danger); border-radius: var(--radius-sm); color: var(--danger-pale); }
.salle-statut-ligne.is-enregistre { color: var(--warn); font-weight: 600; }
.salle-empreinte { display: block; overflow-wrap: anywhere; font-family: ui-monospace, "SFMono-Regular", "Menlo", "Consolas", monospace; font-size: 11px; line-height: 1.5; color: var(--nota-blue-300); }

.salle-refus { display: flex; flex-direction: column; gap: 6px; padding: 10px; background: var(--danger-wash); border: 1px solid var(--danger); border-radius: var(--radius-sm); }
.salle-refus[hidden] { display: none; }
.salle-refus-ligne { margin: 0; font-size: 13px; line-height: 1.45; color: var(--danger-pale); }

.salle-actions { display: flex; flex-direction: column; gap: 8px; }
.salle-btn { font: inherit; font-size: 14px; font-weight: 600; padding: 11px 14px; cursor: pointer; text-align: left; color: var(--midnight-ink); background: var(--midnight-veil); border: 1px solid var(--nota-blue-700); border-radius: var(--radius-sm); }
.salle-btn:hover:not(:disabled) { background: var(--midnight-veil-strong); }
.salle-btn.is-primaire { background: var(--midnight-veil); border-color: var(--nota-blue-400); color: var(--midnight-ink); font-weight: 700; }
.salle-btn.is-primaire:is(:hover, :focus-visible):not(:disabled) { background: var(--midnight-veil); border-color: var(--action-ink); }
.salle-btn.is-discret { background: transparent; font-weight: 500; }
.salle-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.salle-quitter { margin-top: auto; }

/* Sur un téléphone la vidéo passe au-dessus et le rail dessous : le notaire
   conduit rarement depuis un téléphone, le client souvent. */
@media (max-width: 860px) {
  .salle-scene { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(180px, 40vh) minmax(0, 1fr); }
  .salle-rail { border-left: 0; border-top: 1px solid var(--nota-blue-800); }
  .salle-sas { font-size: 28px; }
}

/* L'annonce, dans le carnet et dans l'espace notaire. */
/* Coins carrés comme tout le reste : la marque a tranché contre l'arrondi, et
   une pastille en pilule ferait une exception que rien ne justifie ici. */
.salle-annonce-pastille { display: inline-block; margin: 0 0 8px; padding: 3px 10px; font-size: 12px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: #fff; background: var(--accent-warm); border-radius: var(--radius-xs); }
.salle-annonce-actions { margin-top: 14px; display: flex; flex-wrap: wrap; gap: 8px; }

/* --- Porte « Signature » : la phase 3 --------------------------------------
   La porte n'a PAS de registre à elle : le rail (.wrap), le héros
   (.landing-hero / .landing-copy), le sur-titre (.eyebrow), le lede
   (.landing-lede), la rangée d'actions (.hero-cta), les blocs (.panel), les
   petites lignes (.help) et la modale (dialog / .dialog-pad) sont ceux du
   Carnet. Ne vivent ici que les trois contenus que le Carnet n'a pas :
   l'échelle des phases, les deux tuiles et la liste de faits. Sept couches
   #pane-beta empilées (1 884 → 1 600 → 1 280 px de mesure, une entrée privée,
   une ombre de bouton) ont été SUPPRIMÉES plutôt que corrigées par une
   huitième — n'en rajoutez pas : si quelque chose cloche ici, c'est la règle
   partagée qu'il faut lire (porte-signature-phase3.test.mjs compte ces
   règles et refuse tout sélecteur #pane-beta).
   Refonte 2026-09-20 (« tout l'espace est utilisé », « pas de components trop
   gros », « animations custom ») : la porte n'a toujours AUCUNE entrée à elle.
   Son mouvement est celui du registre partagé — .reveal, .accent-line,
   .rail-draw (« ENTRÉES AU DÉFILEMENT ») — et sa composition une classe
   partagée, .layout-duo, ci-dessous. */

/* `.layout-duo` — une COMPOSITION partagée, pas une règle de la porte : deux
   panneaux côte à côte sur les colonnes du héros (.landing-hero : même partage,
   même seuil de 900 px), étirés à la même hauteur. Ce qui n'est pas un panneau
   (note de garantie, assistance) garde la rangée entière ; un panneau orphelin
   — le dernier d'un nombre impair — aussi, plutôt qu'une case vide à sa droite. */
.layout-duo { grid-template-columns: minmax(0, 1.3fr) minmax(0, 0.8fr); align-items: stretch; }
.layout-duo > .panel:last-of-type:nth-of-type(odd), .layout-duo > :not(.panel) { grid-column: 1 / -1; }
@media (max-width: 900px) {
  .layout-duo { grid-template-columns: minmax(0, 1fr); }
}

.beta-phases { min-width: 0; display: flex; flex-direction: column; }
.beta-phase-list { list-style: none; margin: var(--space-2) 0 0; padding: 0; }
/* Une VRAIE échelle : le marqueur carré de la phase, son nom, puis l'état en
   texte nu sous le nom. Ni pastille ni badge. Le montant (.rail-draw, registre
   partagé) part du marqueur et rejoint le suivant — plein entre deux acquis,
   pointillé vers l'objectif ; la ligne ne fait que le PLACER, par ses trois
   variables. */
.beta-phase {
  --rail-x: calc(var(--space-16) / 2 - 1px); --rail-top: calc(var(--space-16) + var(--space-2)); --rail-bottom: var(--space-2);
  display: grid; grid-template-columns: var(--space-16) minmax(0, 1fr); column-gap: var(--space-8);
  padding-bottom: var(--space-12); text-wrap: pretty;
}
.beta-phase-n {
  grid-row: 1 / 3; align-self: start; display: grid; place-items: center; height: var(--space-16);
  border: 2px solid var(--action-ink); border-radius: var(--radius-sm); background: var(--action-tint);
  font-family: var(--font-display); font-weight: var(--weight-display); font-size: var(--type-h4); line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--action-ink);
}
/* La phase où l'on se trouve est un OBJECTIF : son marqueur est tireté comme le
   montant qui y mène, vide, et cerné d'un halo carré — « vous êtes ici ». */
.beta-phase.is-current > .beta-phase-n { border-style: dashed; background: transparent; box-shadow: 0 0 0 var(--space-2) var(--action-tint); }
.beta-phase-name {
  padding-top: var(--space-2); font-family: var(--font-display); font-weight: var(--weight-display);
  font-size: var(--type-h4); line-height: var(--type-h4-lh); letter-spacing: var(--type-h4-ls); color: var(--ink);
}
/* Les deux blocs : une colonne — le titre, son contenu, et l'action au PIED de
   la carte (.layout-duo étire les deux cartes à la même hauteur). Les tuiles
   sont des cartes en retrait coiffées du trait d'accent de 3 px du guide, qui
   se trace à l'arrivée du bloc (.accent-line) : indigo, puis violet. */
.beta-block { display: flex; flex-direction: column; gap: var(--space-6); min-width: 0; }
.beta-block > .help { margin: 0 0 var(--space-3); }
.beta-tiles { flex: 1; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); gap: var(--space-8); }
.beta-tile {
  --accent-line: var(--accent-blue);
  display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; padding: var(--pad-card-lg);
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-inset);
}
.beta-tile:nth-child(2) { --accent-line: var(--accent-purple); }
.beta-tile > p { margin: 0; max-width: 52ch; color: var(--ink-muted); }
/* Trois faits, un filet entre chacun, une puce CARRÉE (le registre). */
.beta-facts { list-style: square; margin: 0; padding-left: var(--space-9); display: grid; gap: var(--space-5); color: var(--ink-muted); text-wrap: balance; }
.beta-facts > li + li { padding-top: var(--space-5); border-top: 1px solid var(--border); }
.beta-facts + .btn { align-self: flex-start; margin-top: auto; }
/* La modale : le sous-titre de la démonstration respire, les petites lignes
   ferment leur paragraphe, et le cartouche de la salle d'essai se lit comme un
   cartouche — une carte en retrait, pas un sixième paragraphe. */
.beta-details > h4 {
  font-family: var(--font-display); font-weight: var(--weight-display);
  font-size: var(--type-h4); line-height: var(--type-h4-lh); letter-spacing: var(--type-h4-ls);
  margin: var(--space-12) 0 var(--space-4);
}
.beta-details > .help { margin: 0 0 var(--space-6); }
/* Les deux actions ouvrent la modale ; leurs notes d'état, vides, ne prennent
   pas de place — la marge vit donc sous la rangée, pas sur les notes. Le lien
   vers la démonstration technique ferme son paragraphe de la même façon. */
.beta-details > .salle-annonce-actions, .beta-details > .btn { margin: 0 0 var(--space-8); }
.beta-trust-collapsed { padding: var(--pad-card-lg); border-radius: var(--radius); background: var(--surface-inset); }
/* fin — porte « Signature » (refonte 2026-09-20) */

/* Le formulaire d'inscription bêta : un champ et un bouton sur une ligne,
   comme les autres formulaires de capture du site. */
.salle-annonce-label {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  font-size: var(--type-h3);
  color: var(--ink);
  margin: 0 0 var(--space-3);
}
.beta-inscription-fields {
  display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap;
}
.beta-inscription-fields > input[type="email"] {
  flex: 1 1 240px; min-width: 0;
  font: inherit; padding: var(--space-2) var(--space-3);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink);
}
.beta-inscription-fields > input[type="email"]:focus-visible {
  outline: 2px solid var(--brand); outline-offset: 1px;
}
.beta-inscription-msg { margin: var(--space-3) 0 0; }

/* --- Notary landing polish ----------------------------------------------
   The door opens on the SAME surface the Carnet opens on (owner, 2026-09-12).
   ONE copy of each rule (the three stacked « final » layers that stood here
   redefined the card surface four times and stripped the panel the base rule
   gives .nc-live — removed 2026-09-18, the base rules now say it once). */

/* A heading is ink on every surface. Blue is for an informational mention (an
   amount, a link, a badge), never for the label a section is read by. */
#pane-notaires #notary-console .h-sub {
  color: var(--ink);
}

#pane-notaires .nc-live-card {
  border-color: var(--border);
  border-radius: var(--radius);
}

/* The act's name stays ink; the amount carries the notary accent. */
#pane-notaires .nc-live-amt {
  color: var(--action-ink);
  font-weight: 700;
}

#pane-notaires .nc-auth-cta {
  background: transparent;
  border-color: var(--action-ink);
  color: var(--action-ink);
  box-shadow: none;
}
#pane-notaires .nc-auth-cta:hover {
  background: var(--action-tint);
  border-color: var(--action-ink);
  color: var(--action-ink);
}

#pane-notaires .nc-signup-open {
  color: var(--action-ink);
}



/* --- Account menu refinement ---------------------------------------------
   Keep the account hub calm and flat: the shadow separates it from the page,
   while the identity row remains part of the menu instead of becoming a card
   inside another card. */
.acct-panel {
  width: min(368px, calc(100vw - 24px));
  padding: 10px;
  border: 0;
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
}
.acct-panel-head {
  align-items: center;
  gap: 8px;
  padding: 2px;
}
.acct-panel-head .acct-head {
  gap: 11px;
  padding: 10px;
  border: 0;
  background: transparent;
}
.acct-panel-head .acct-head:hover,
.acct-panel-head .acct-head:focus-visible {
  background: var(--action-tint);
}
.acct-avatar {
  width: 40px;
  height: 40px;
  background: var(--surface);
  border-color: var(--border-strong);
}
.acct-item-title { font-size: 15px; letter-spacing: -0.01em; }
.acct-item-sub { font-size: 12px; line-height: 1.35; }
.acct-role { margin-top: 3px; padding: 2px 7px; background: transparent; }
.acct-close {
  width: 34px;
  height: 34px;
  border: 1px solid transparent;
  border-radius: var(--radius);
}
.acct-close:hover,
.acct-close:focus-visible {
  border-color: var(--border);
  background: var(--action-tint);
}
.acct-sep { margin: 8px 4px; background: color-mix(in srgb, var(--border-strong) 70%, transparent); }
.acct-actions { gap: 3px; padding: 1px 2px; }
.acct-action {
  min-height: 42px;
  padding: 8px 10px;
  border: 1px solid transparent;
  transition: background-color var(--motion-fast) var(--ease-ui), border-color var(--motion-fast) var(--ease-ui), transform var(--motion-fast) var(--ease-ui);
}
.acct-action svg {
  width: 18px;
  height: 18px;
  color: var(--action-ink);
}
.acct-action:hover,
.acct-action:focus-visible {
  border-color: var(--border);
  background: var(--action-tint);
}
.acct-action:hover { transform: translateX(2px); }
.acct-action:last-child {
  margin-top: 4px;
  border-top-color: var(--border);
  color: var(--ink-muted);
}
.acct-action:last-child svg { color: var(--ink-muted); }
.acct-notifs { margin-top: 2px; }
.acct-panel .notif-head {
  padding: 5px 10px 4px;
  color: var(--ink-muted);
}
.acct-panel .notif-list {
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-veil);
}
.acct-panel .notif-item {
  padding: 9px 34px 9px 10px;
  border-bottom-color: var(--border);
}
.acct-panel .notif-item:last-child { border-bottom: 0; }
.acct-panel .notif-item.is-unread { background: var(--surface-hover); }
.acct-legal {
  gap: 2px;
  padding: 0 2px 1px;
}
.acct-legal-link { padding: 5px 7px; }

@media (max-width: 899.98px) {
  .acct-panel {
    position: fixed;
    top: calc(var(--header-h) + 8px);
    right: 8px;
    width: min(360px, calc(100vw - 16px));
  }
}

/* Final visual pass: these rules intentionally sit after the responsive intro
   rules so the calm chooser treatment wins at every viewport size. */
.language-control { opacity: 0 !important; pointer-events: auto !important; }
#lang-toggle.language-control {
  position: relative !important;
  top: auto; right: auto; width: 1px; height: 1px;
  margin: 0; padding: 0; overflow: visible; border: 0;
  z-index: 1;
}
.mnav-pref.language-control {
  min-height: 1px; height: 1px; margin-block: -1px !important; overflow: visible;
}
#lang-toggle.language-control { min-width: 0 !important; }
.analytics-consent {
  left: 50%; right: auto; bottom: 16px;
  width: min(560px, calc(100vw - 32px)); max-width: none;
  padding: 12px 14px;
  transform: translateX(-50%);
  background: var(--surface);
  border-color: var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.analytics-consent p { margin-bottom: 8px; font-size: 12px; line-height: 1.45; }
.analytics-consent button, #analytics-preferences:not(.footer-link) { padding: 7px 10px; margin-right: 4px; font-size: 12px; }
.analytics-consent a { font-size: 12px; }
.toast {
  bottom: 18px;
  padding: 10px 14px;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
  font-size: 13px;
}

/* Keep the locale control discoverable in the real header and mobile drawer.
   The arrival-film copies remain intentionally quiet, but the application
   shell must always expose the FR | EN choice promised by the product. */
.language-control {
  opacity: 1 !important;
  pointer-events: auto !important;
}

#lang-toggle.language-control {
  position: relative !important;
  width: auto;
  height: auto;
  min-width: auto !important;
  margin: 0;
  padding: 2px;
  overflow: visible;
}

.mnav-pref.language-control {
  min-height: 0;
  height: auto;
  margin-block: 0 !important;
  overflow: visible;
}

/* The section tint should whisper blue against the white card. The white
   parent and the 24 px sibling margin are the visual separator. */
#day-dialog .offer-sec,
#day-dialog .o-criteria .crit-sec {
  background: color-mix(in srgb, var(--brand-bright) 6%, var(--surface));
}

/* Information is an affordance, but the glyph itself is not another boxed
   card: keep it brand-coloured and remove the enclosing ring. */
#day-dialog .itip-btn,
#day-dialog .itip-btn:hover,
#day-dialog .itip[data-open='true'] .itip-btn {
  border: 0;
  background: transparent;
  color: var(--action-ink);
}

/* The beta note is a signed-out discovery cue; an authenticated notary gets
   the account-scoped preparation card instead. */

/* Lead with calendar subscription; account access follows it in the rail. */

/* Touch targets apply at every width; keep these outside the wide-only
   authenticated landing layout above. */
.nc-conformite-link,
.sup-mail-open {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
.sup-text { min-height: 44px; }


@media (max-width: 640px) {
  /* On a one-column phone inventory the overflow tile follows the last real
     card. Top-aligning its message keeps the tile useful without a centered
     dead pocket between two consecutive demand rows. */
  #pane-notaires .nc-live-more { justify-content: flex-start; }
}


/* Calendar subscription is the first action on compact notary landings. */

/* The public notary landing leads with the calendar and available offers.
   Keep these rules scoped to the signed-out state; the working console retains
   its full-width layout after authentication. */
/* Render offers together: staggered fades left temporary holes on refresh. */
.nc-calendar-secondary { min-width: 0; }
.nc-calendar-secondary > summary { display: list-item; min-height: 44px; padding-block: var(--space-3); box-sizing: border-box; cursor: pointer; font-weight: 600; color: var(--ink); }
#notary-calendar-access[open] > form { margin: 0 0 24px; max-width: 560px; animation: fadeUp var(--motion-ui) var(--ease-ui) both; }
/* Porte du compte FERMÉE (face publique) : une ligne, pas un panneau vide. */
#notary-console:has(> #notary-calendar-access:not([open]):not([hidden])) { padding-block: var(--space-4); }
#pane-notaires > .wrap:has(#notary-authed:not([hidden])) .notary-landing-right { display: contents; }
/* Keep the pane's navigation target available to assistive technology while
   letting the work start immediately below the navigation bar. */
#pane-notaires > .wrap:has(#notary-authed:not([hidden])) .intro--hero {
  position: absolute;
  width: 1px;
  height: 1px;
  min-height: 0;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
#pane-notaires > .wrap:has(#notary-authed:not([hidden])) #notary-console {
  width: 100%;
  margin: 0;
  padding: var(--space-7) 0 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: none;
}
#pane-notaires .nc-card,
#pane-notaires .nc-live-card {
  background: var(--nc-offer-surface);
  box-shadow: var(--shadow-sm);
  animation: none;
  transition: background-color var(--motion-fast) var(--ease-ui), border-color var(--motion-fast) var(--ease-ui), box-shadow var(--motion-fast) var(--ease-ui);
}
#pane-notaires .nc-card:hover,
#pane-notaires .nc-live-card:hover {
  transform: none;
  background: var(--nc-offer-hover);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-sm);
}
@media (pointer: coarse) {
  .nc-calendar-teaser .nc-calendar-play { min-height: 44px; }
}
/* The support bubble is fixed to the bottom-right; between 701 and 1080 it
   shares that column with the teaser's offer card and covered about half the
   amount on first paint (measured at 768×1024: the FAB starts at x=704, the
   amount box runs 666→740). The calendar reserves the column rather than the
   bubble moving — .sup-wrap is global, and nudging it to dodge one card at one
   width only pushes the collision somewhere else. 48px FAB + 16px rail. */
@media (min-width: 701px) and (max-width: 1080px) {
  #nc-calendar-teaser { padding-right: 64px; }
}

/* Human handoff is a chat action with the same inset as the topic browser. */
.sup-panel > #chat-human { margin-inline: 14px; align-self: flex-start; }

/* The native agenda shares the page surface; only the standalone film needs
   rounded clipping. Native controls and keyboard outlines remain visible. */
.nc-calendar-teaser {
  position: relative; isolation: isolate; margin: 20px auto; width: 100%; max-width: 1100px;
  min-width: 0; align-self: center;
  /* Sans cadre (propriétaire, 2026-09-14 : « avoid border like this… make them
     seamless ») : un trait à la couleur de marque plus une ombre encadraient le
     calendrier comme une image collée sur la page. Il n'a plus de bord — il
     repose sur le fond de la page et c'est la grille elle-même qu'on lit. */
  border: 0; background: transparent; box-shadow: none;
}
.nc-calendar-teaser:not([data-native]) { overflow: hidden; border-radius: var(--radius-lg); }

/* The phone calendar keeps its month readable; the offer gets its own row
   instead of shrinking the desktop film's text into seven tiny columns. */
/* Sans couture : le calendrier repose sur le fond de la page, sans plaque ni
   trait qui le découpe. Seule la grille et ses chiffres portent la scène. */
.nc-mobile-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 8px 16px; margin-bottom: 16px; }
.nc-mobile-month { font-family: var(--font-display); font-size: 22px; line-height: 1.3; font-weight: 700; white-space: nowrap; }
.nc-mobile-legend { display: flex; align-items: center; gap: 6px; margin: 0; font-size: 12px; color: var(--ink-muted); font-weight: 500; white-space: nowrap; }
.nc-mobile-legend::before { content: ''; flex-shrink: 0; width: 6px; height: 6px; border-radius: 50%; background: var(--action-ink); }
.nc-mobile-week, .nc-mobile-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
.nc-mobile-week { padding-bottom: 10px; color: var(--ink-muted); font-size: 11px; text-align: center; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; border-bottom: 1px solid var(--border); margin-bottom: 4px; }
.nc-mobile-grid { gap: 2px 0; }
.nc-mobile-day { appearance: none; display: grid; place-items: center; align-content: center; gap: 3px; min-width: 0; height: 44px; padding: 0; font: inherit; font-size: 14px; font-variant-numeric: tabular-nums; color: inherit; background: transparent; border: 1px solid transparent; border-radius: var(--radius-sm); transition: background-color var(--motion-enter) var(--ease-ui), border-color var(--motion-enter) var(--ease-ui); position: relative; cursor: default; }
.nc-mobile-day::before { content: ''; position: absolute; inset: 0; border: 1px solid var(--border); border-radius: var(--radius-sm); pointer-events: none; opacity: 0.4; }
.nc-mobile-day::after { content: ''; width: 5px; height: 5px; border-radius: 50%; background: transparent; transition: background var(--motion-enter) var(--ease-ui); position: absolute; bottom: 6px; left: 50%; transform: translateX(-50%); }
.nc-mobile-day.has-request { cursor: pointer; }
.nc-mobile-day.has-request:is(:hover, :focus-visible) { background: var(--action-tint); }
.nc-mobile-day.has-request:hover::before { opacity: 0.6; border-color: var(--action-ink); }
.nc-mobile-day.has-request::after { background: var(--action-ink); }
.nc-mobile-day.is-outside { color: var(--ink-muted); opacity: .35; }
.nc-mobile-day.is-outside::before { opacity: 0.2; }
.nc-mobile-day.is-selected { font-weight: 700; border-color: var(--action-ink); background: var(--action-tint-strong); color: var(--action-ink); box-shadow: 0 0 0 1px var(--action-ink); }
.nc-mobile-day.is-selected::before { opacity: 0; }
.nc-mobile-day.is-selected::after { background: var(--action-ink); }
.nc-mobile-number { font-size: 14px; font-variant-numeric: tabular-nums; }
.nc-mobile-offer { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 6px 12px; margin-top: 14px; padding-top: 14px; border-top: 2px solid var(--action-ink); }
.nc-mobile-date { grid-column: 1 / -1; font-size: 12px; color: var(--ink-muted); font-weight: 500; }
.nc-mobile-date::first-letter { text-transform: uppercase; }
.nc-mobile-service { align-self: center; font-size: 15px; font-weight: 700; overflow-wrap: anywhere; }
.nc-mobile-amount { align-self: center; font-size: 22px; font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--accent-warm); font-weight: 700; }
.nc-mobile-details { margin-top: var(--space-6); }
.nc-mobile-cta { min-height: 44px; max-width: 100%; white-space: normal; }

@media (max-width: 600px) {
  /* Au téléphone la preuve est une LISTE : une demande par ligne, le montant
     à droite, comme le pouls du carnet. */
  #pane-notaires #notary-live-grid { grid-template-columns: minmax(0, 1fr); grid-auto-rows: auto; gap: 8px; }
  #pane-notaires .nc-live-card { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: 'svc amt' 'meta pill'; align-items: center; align-content: center; gap: 8px 12px; padding: 14px; }
  #pane-notaires .nc-live-card .nc-live-svc-name { font-size: 14px; white-space: normal; overflow: visible; }
  #pane-notaires .nc-live-card .nc-live-amt { justify-self: end; font-size: 20px; }
  #pane-notaires .nc-live-card .nc-live-meta { font-size: 12px; }
  #pane-notaires .nc-live-more { min-height: 76px; }
}

/* ONE HEADER LAYOUT — for every public entry point, not for three of them by
   name. Keyed on the classes alone: a door that carries .landing-hero gets the
   register, wherever it lives. The ID-scoped form this replaces silently left
   #pane-beta outside the block, which is how the four doors drifted apart. */
.landing-hero {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 0.8fr);
  gap: clamp(16px, 2vw, 28px);
  align-items: start;
  min-height: 0;
  margin: 0;
  padding: var(--intro-pad-top) 0;
  text-align: left;
}
/* A soft radial glow fills the empty dark space behind the hero copy — two
   overlapping gradients at low opacity so the surface breathes without
   distracting from the content. Scoped to the carnet pane. */
#pane-carnet .landing-hero {
  background:
    radial-gradient(ellipse 60% 50% at 18% 40%, var(--brand-tint) 0%, transparent 70%),
    radial-gradient(ellipse 40% 45% at 75% 60%, rgb(var(--nota-blue-400-rgb) / 0.03) 0%, transparent 70%);
}
.landing-copy {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: flex-start;
  min-width: 0;
  width: 100%;
  max-width: none;
}
.landing-copy > .eyebrow { margin: 0 0 var(--space-8); }
.landing-copy > h1 {
  width: 100%;
  max-width: none;
  margin: 4px 0 0;
  font-size: var(--type-h1);
  line-height: var(--type-h1-lh);
  text-wrap: balance;
}
.landing-copy > .landing-lede {
  width: 100%;
  max-width: 47ch;
  margin: var(--space-8) 0 0;
  font-size: var(--type-lead);
  line-height: var(--type-lead-lh);
  color: var(--ink-muted);
  text-wrap: pretty;
}
/* The market and native agenda get their own row before the right column
   becomes cramped. The homepage market keeps two readable service columns. */
@media (min-width: 768px) and (max-width: 1279.98px) {
  #pane-carnet .landing-hero,
  #pane-notaires .landing-hero { grid-template-columns: minmax(0, 1fr); }
  #pane-carnet .pulse-rows { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-6) var(--space-8); }
  #pane-carnet .pulse-row { grid-template-columns: auto minmax(24px, 1fr); row-gap: var(--space-2); }
  #pane-carnet .pulse-figs { grid-column: 1 / -1; grid-row: 3; justify-content: space-between; }
  #pane-carnet .pulse-fig { align-items: flex-start; }
  #pane-carnet .pulse-fig:last-child { align-items: flex-end; }
}
@media (max-width: 900px) {
  .landing-hero {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(18px, 3vw, 26px);
    padding-block: var(--space-7);
  }
}
@media (max-width: 680px) {
  .landing-copy > h1 { font-size: var(--type-h1-compact); }
}

/* The header and subscription share the left column; the film starts beside
   the header. A shared grid avoids reserving an empty title row above it.
   De-scoped with the block above: the notary hero reads as one column in both
   the signed-out and signed-in states, rather than only while the gate shows. */

/* Profile workspace: a quiet navigation rail and readable, consistent sections. */
#pane-profil > .wrap { max-width: 1280px; }
#pane-profil .profil-intro { margin-bottom: 28px; }
#pane-profil .profil-intro h1 { font-size: var(--type-h1-compact); }
#pane-profil .profil-intro p { max-width: 58ch; }
.profil-layout { display: grid; grid-template-columns: 204px minmax(0, 1fr); gap: 32px; align-items: start; }
.profil-nav { position: sticky; top: calc(var(--sticky-top) + 16px); display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.profil-nav > .eyebrow { margin: 0 0 12px 12px; font-size: 10px; }
.profil-nav-item {
  display: flex; align-items: center; gap: 10px; width: 100%; min-height: 48px; padding: 8px 12px;
  border: 1px solid transparent; border-radius: var(--radius-sm); background: transparent;
  font: inherit; font-size: 14px; font-weight: 600; text-align: left; color: var(--ink-muted); cursor: pointer;
}
.profil-nav-item .profil-card-ic { background: transparent; color: inherit; }
.profil-nav-item:hover, .profil-nav-item:focus-visible { background: var(--action-tint); color: var(--action-ink); border-color: var(--border-strong); }
.profil-nav .account-tour-replay { order: 1; margin-top: 20px; white-space: normal; align-self: stretch; }
#pane-profil .profil-stack { gap: 24px; min-width: 0; }
#pane-profil .profil-card {
  min-width: 0; padding: clamp(18px, 2.5vw, 28px); gap: 20px;
  border-radius: var(--radius-lg); background: var(--surface-veil);
  scroll-margin-top: calc(var(--sticky-top) + 20px);
}
#pane-profil .profil-card:focus { outline: 2px solid var(--brand); outline-offset: 4px; }
#pane-profil .profil-card-head { display: grid; grid-template-columns: 36px minmax(0, 1fr); gap: 4px 12px; }
#pane-profil .profil-card-head > .profil-card-ic { grid-row: 1 / span 2; width: 36px; height: 36px; background: var(--brand-tint-solid); }
#pane-profil .profil-card-title { font-size: var(--type-h3); line-height: var(--type-h3-lh); letter-spacing: var(--type-h3-ls); }
#pane-profil .profil-card-sub { grid-column: 2; max-width: 64ch; font-size: 13px; line-height: 1.55; }
#pane-profil .profil-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px; }
#pane-profil .profil-fields input { min-height: 46px; background: var(--surface); }
#pane-profil .profil-fields .help { font-size: 12px; }
.profil-save-status { padding-top: 14px; border-top: 1px solid var(--border); font-size: 12px; color: var(--ink-muted); }
.profil-save-status::before { content: '✓'; margin-right: 8px; color: var(--ok); }
.profil-fields .profil-field-error { color: var(--danger); }
.profil-fields input[aria-invalid='true'] { border-color: var(--danger); }
#pane-profil .profil-switches { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 24px; }
#pane-profil .switch-row { min-height: 62px; padding: 12px 0; border-bottom: 1px solid var(--border); gap: 12px; }
#pane-profil .switch-title { flex: 1; margin: 0; font-size: 13px; line-height: 1.45; cursor: pointer; }
#pane-profil .switch { flex-shrink: 0; }
.profil-email-prefs { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 20px; }
.profil-email-prefs > p { flex: 1 1 240px; max-width: 52ch; }
.profil-email-prefs .btn { min-height: 44px; }
#pane-profil .profil-empty { gap: 20px; padding: 18px; background: var(--surface-inset); border: 1px solid var(--border); }
#pane-profil .profil-empty-text { max-width: 48ch; line-height: 1.6; }
#pane-profil .profil-empty .btn { flex-shrink: 0; min-height: 44px; white-space: normal; }
#pane-profil .profil-doc-chips { gap: 8px; margin: 0; }
#pane-profil .profil-doc-chips .chip { min-height: 42px; white-space: normal; text-align: left; }
#pane-profil .doc-summary { padding: 14px; background: var(--surface-inset); border: 1px solid var(--border); }
#pane-profil .my-offers { margin: 0; }
#pane-profil .profil-referral { border-color: var(--border-strong); }
.profil-rewards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); border: 1px solid var(--border-strong); background: var(--brand-tint-solid); }
.profil-reward { display: grid; gap: 8px; padding: 20px; min-width: 0; }
.profil-reward + .profil-reward { border-left: 1px solid var(--border-strong); background: var(--brand-tint-solid-strong); }
.profil-reward-label { font-size: 12px; font-weight: 600; color: var(--ink-muted); }
.profil-reward-amount { font-family: var(--font-mono); font-size: var(--type-h2); line-height: 1.2; letter-spacing: -.04em; color: var(--brand-on-surface); }
.profil-reward .help { font-size: 12px; line-height: 1.5; }
.profil-referral .parr-code-row { flex-wrap: wrap; gap: 8px 14px; }
.profil-referral .parr-code { font-size: 24px; overflow-wrap: anywhere; }
.profil-status { display: inline-flex; align-items: center; gap: 6px; padding: 4px 8px; width: fit-content; font-size: 11px; font-weight: 700; color: var(--ink); background: var(--surface-inset); border: 1px solid var(--border); }
.profil-status::before { content: ''; width: 5px; height: 5px; background: currentColor; border-radius: 50%; }
.profil-referral .partner-link-row { margin: 0; gap: 10px; }
.profil-referral .partner-link-row code { flex: 1 1 100%; min-width: 0; padding: 14px 16px; font-size: 14px; user-select: all; }
.profil-referral .btn { min-height: 44px; }
.profil-message { padding: 16px 0; border-block: 1px solid var(--border); }
.profil-message > summary { min-height: 28px; font-size: 14px; font-weight: 600; cursor: pointer; color: var(--ink); }
.profil-message .partner-msg-text { margin-top: 16px; font-size: 14px; line-height: 1.65; }
.profil-referral-followup { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; }
.profil-referral-followup .help { flex-basis: 100%; margin: 0; }
.profil-referral-email { flex: 1 1 180px; font-size: 13px; overflow-wrap: anywhere; color: var(--ink-muted); }

@media (max-width: 900px) {
  .profil-layout { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  .profil-nav { position: static; flex-direction: row; flex-wrap: wrap; gap: 6px; padding-bottom: 18px; border-bottom: 1px solid var(--border); }
  .profil-nav > .eyebrow { flex-basis: 100%; margin: 0 0 6px; }
  .profil-nav-item { width: auto; min-height: 44px; padding: 6px 10px; border-color: var(--border); background: var(--surface-inset); font-size: 12px; }
  .profil-nav-item .profil-card-ic { width: 18px; height: 18px; }
  .profil-nav .account-tour-replay { margin: 0; min-height: 44px; }
}
@media (max-width: 560px) {
  #pane-profil .profil-intro { margin-bottom: 20px; }
  #pane-profil .profil-card { gap: 18px; padding: 18px 16px; }
  #pane-profil .profil-fields, #pane-profil .profil-switches { grid-template-columns: minmax(0, 1fr); }
  #pane-profil .profil-empty { flex-direction: column; align-items: stretch; padding: 16px; }
  #pane-profil .profil-card-head { grid-template-columns: 30px minmax(0, 1fr); gap: 8px 10px; }
  #pane-profil .profil-card-head > .profil-card-ic { width: 30px; height: 30px; grid-row: 1; }
  #pane-profil .profil-card-sub { grid-column: 1 / -1; }
  .profil-reward { padding: 14px 12px; }
  .profil-email-prefs .btn { width: 100%; }
  .profil-referral .partner-link-row .btn { flex: 1; }
  .profil-referral .partner-link-row code { font-size: 12px; }
}

/* Calm depth and responsive feedback across the public experience.
   Only the panel paint is translucent; readable text and inputs stay solid. */
.sub-card, .nc-card, #pane-profil .profil-card {
  box-shadow: var(--shadow);
  transition: border-color var(--motion-ui) var(--ease-ui), box-shadow var(--motion-ui) var(--ease-ui);
}
.sub-card:focus-within,
#pane-profil .profil-card:focus-within { border-color: var(--border-strong); box-shadow: var(--shadow-lg); }
h1, h2, h3 { text-wrap: balance; }
@media (prefers-reduced-motion: no-preference) {
  .btn, .sub-btn, .profil-nav-item {
    transition: background-color var(--motion-fast) var(--ease-ui), border-color var(--motion-fast) var(--ease-ui),
      color var(--motion-fast) var(--ease-ui), box-shadow var(--motion-ui) var(--ease-ui), transform var(--motion-fast) var(--ease-ui);
  }
  #pane-profil.is-active .profil-card { animation: heroIn var(--motion-enter) var(--ease-ui) both; }
  #pane-profil.is-active .profil-card:nth-child(2) { animation-delay: 50ms; }
  #pane-profil.is-active .profil-card:nth-child(3) { animation-delay: 100ms; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important; scroll-behavior: auto !important;
  }
  .brand:hover .brand-mark img, .brand:hover .brand-mark-svg { transform: none; }
}

/* Calendar controls and dates share the hero’s left rail. */
#carnet-panel :is(.cal-toolbar, .cal-grid, .filterbar, .legend) { padding-inline: 0; }
#carnet-panel .legend { padding-left: var(--space-3); }

/* ==========================================================================
   Speed-dial FAB: one button expands to reveal guide, chat, voice
   ========================================================================== */
.speed-dial {
  position: fixed;
  bottom: var(--help-edge-gap);
  right: var(--help-edge-gap);
  z-index: 50;
  display: flex;
  flex-direction: column-reverse;
  align-items: flex-end;
  gap: var(--space-5);
}

.speed-dial-main {
  width: var(--help-control-size);
  height: var(--help-control-size);
  border-radius: 50%;
  border: 0;
  background: var(--help-fill, var(--brand));
  color: #fff;
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background var(--motion-fast) var(--ease-ui), color var(--motion-fast) var(--ease-ui), box-shadow var(--motion-fast) var(--ease-ui), transform var(--motion-fast) var(--ease-ui);
  box-shadow: 0 4px 16px -4px rgb(38 73 97 / .45);
  z-index: 2;
}

.speed-dial-main svg {
  width: 26px;
  height: 26px;
}

.speed-dial-main:is(:hover, :focus-visible) {
  background: var(--help-hover, color-mix(in srgb, var(--ink) 85%, #fff));
  color: #fff;
  transform: scale(1.06);
  box-shadow: 0 6px 24px -4px rgb(38 73 97 / .55);
}

.speed-dial-main[aria-expanded="true"] {
  background: var(--help-hover, color-mix(in srgb, var(--ink) 85%, #fff));
  color: #fff;
  box-shadow: 0 6px 24px -4px rgb(38 73 97 / .55);
}

.speed-dial-options {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-2);
  min-width: 180px;
  max-width: calc(100vw - 2 * var(--space-8));
  padding: var(--space-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}

.speed-dial-options[hidden] {
  display: none;
}

.speed-dial-option {
  width: 100%;
  min-height: 44px;
  padding: var(--space-4) var(--space-6);
  gap: var(--space-6);
  border-radius: var(--radius);
  border: 0;
  background: transparent;
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: flex-start;
  cursor: pointer;
  transition: background var(--motion-fast) var(--ease-ui), color var(--motion-fast) var(--ease-ui);
  position: relative;
}

.speed-dial-option:hover, .speed-dial-option:focus-visible {
  background: color-mix(in srgb, var(--brand, #1a5490) 8%, var(--surface, #fbfdfd));
  color: var(--brand, #1a5490);
}
.speed-dial-main:focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; }
.speed-dial-option:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; }
.speed-dial-option svg { flex: none; color: var(--brand); }

.speed-dial-label {
  white-space: nowrap;
  font-size: var(--type-h4);
  font-weight: 600;
  color: inherit;
}

/* Stagger animation for options appearing */
.speed-dial-options:not([hidden]) .speed-dial-option {
  animation: speed-dial-in var(--motion-fast) var(--ease-ui) both;
}
.speed-dial-options:not([hidden]) .speed-dial-option:nth-child(1) { animation-delay: 0s; }
.speed-dial-options:not([hidden]) .speed-dial-option:nth-child(2) { animation-delay: 0.05s; }
.speed-dial-options:not([hidden]) .speed-dial-option:nth-child(3) { animation-delay: 0.1s; }

@keyframes speed-dial-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Role modal — the « ? » FAB opens a single dialog asking who you are.
   Brand-aligned: outlined cards, no fills, smooth entrance, Sora display. */
.role-modal {
  border: none;
  border-radius: var(--radius-lg);
  background: var(--surface, #fbfdfd);
  color: var(--ink, #173b52);
  padding: 0;
  max-width: 420px;
  width: calc(100% - 32px);
  box-shadow: 0 24px 64px -16px rgb(0 0 0 / .25), 0 0 0 1px rgb(0 0 0 / .04);
  overflow: hidden;
}
.role-modal::backdrop {
  background: rgb(0 0 0 / .35);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.role-modal[open] {
  animation: role-modal-in var(--motion-fast, .18s) var(--ease-ui, ease-out) both;
}
@keyframes role-modal-in {
  from { opacity: 0; transform: scale(.96) translateY(8px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}
.role-modal-inner {
  padding: 32px 28px 28px;
  position: relative;
}
.role-modal-head {
  text-align: center;
  margin-bottom: 28px;
}
.role-modal-mark {
  color: var(--brand, #386888);
  margin-bottom: 14px;
}
.role-modal-title {
  color: var(--ink, #173b52);
  margin: 0;
}
.role-modal-subtitle {
  margin-top: 6px;
  font-size: 15px;
  color: var(--ink-muted, #526b78);
}
.role-modal-options {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.role-modal-option {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px 18px;
  border: 1px solid var(--border, #c5d8df);
  border-radius: var(--radius-lg);
  background: transparent;
  color: var(--ink, #173b52);
  cursor: pointer;
  text-align: left;
  width: 100%;
  transition: border-color var(--motion-fast) var(--ease-ui), background var(--motion-fast) var(--ease-ui), transform var(--motion-fast) var(--ease-ui);
}
.role-modal-option:is(:hover, :focus-visible) {
  border-color: var(--brand, #386888);
  background: color-mix(in srgb, var(--brand, #386888) 5%, transparent);
  transform: translateY(-1px);
}
.role-modal-option:focus-visible {
  outline: 2px solid var(--focus-ring, rgb(56 104 136 / .45));
  outline-offset: 2px;
}
.role-modal-option svg {
  flex: none;
  color: var(--brand, #386888);
}
.role-modal-option-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.role-modal-option-label {
  font-family: var(--font-display, 'Sora', system-ui, sans-serif);
  font-weight: 700;
  font-size: 15px;
}
.role-modal-option-desc {
  font-size: 13px;
  color: var(--ink-muted, #526b78);
  line-height: 1.4;
}
@media (prefers-reduced-motion: reduce) {
  .role-modal, .role-modal[open] { animation: none; }
  .role-modal-option { transition: none; }
}

/* Hide old FABs when speed-dial is present */
.guide-fab { display: none; }
.sup-fab { display: none; }

@media (max-width: 768px) {
  :root { --help-control-size: 48px; --help-edge-gap: 16px; }
}
@media (prefers-reduced-motion: reduce) {
  .speed-dial-main, .speed-dial-option { transition: none; }
  .speed-dial-options:not([hidden]) .speed-dial-option { animation: none; }
}

/* ==========================================================================
   AI training disclosure
   ========================================================================== */

/* At the page end, the floating launcher has its own clear strip.
   Standalone pages and help that already occupies the flow need no reserve. */
body:has(> .speed-dial) > .site-footer { padding-bottom: calc(var(--help-control-size) + var(--help-edge-gap) + var(--space-8)); }
body:has(.client-walk:not([hidden])) > .site-footer { padding-bottom: var(--space-8); }

/* The homepage leaves a safe strip beside prices for its visible launcher.
   In the notary console, help stays in the flow beside the full-width calendar. */
@media (max-width: 600px) {
  #pane-carnet .pulse-rows { padding-inline-end: calc(44px + var(--space-6)); }
  body:has(#pane-notaires:not([hidden])) > .site-footer { padding-bottom: var(--space-8); }
  body:has(#pane-notaires:not([hidden])) .speed-dial {
    position: relative; inset: auto; margin: var(--space-4); margin-inline-start: auto;
    width: fit-content;
  }
}

/* Two audiences, one product. Color identifies the path without boxed panels.
   The client path is the primary action — filled border + brand tint background
   makes it the obvious first click. The notary path stays outlined/ghost so the
   two user types are never visually confused. */
.experience-paths { position: relative; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-6); }
/* Merged button component: label + action in one clickable unit.
   Outlined, no fill, with a clear hover overlay for mouse interaction. */
.experience-path {
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  padding: 20px 24px;
  border-radius: var(--radius-lg);
  border: 2px solid var(--border);
  background: transparent;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  transition: background var(--motion-fast, 0.2s), border-color var(--motion-fast, 0.2s), transform var(--motion-fast, 0.2s), box-shadow var(--motion-fast, 0.2s);
}
.experience-path:is(:hover, :focus-visible) {
  background: var(--brand-tint, rgba(26, 84, 144, 0.06));
  border-color: var(--brand, #1a5490);
  transform: translateY(-2px);
  box-shadow: var(--shadow-sm, 0 2px 8px rgba(0, 0, 0, 0.08));
}
.experience-path:active {
  transform: translateY(0);
  box-shadow: none;
}
.experience-label {
  display: flex;
  align-items: center;
  gap: var(--space-3, 12px);
  font-size: 16px;
  font-weight: 700;
  color: var(--ink, #173b52);
  letter-spacing: 0.01em;
}
.experience-label svg { flex: none; }
.experience-action {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink, #173b52);
  letter-spacing: 0.01em;
  padding-left: 4px;
}
/* Client path: brand blue accent on hover only — text stays dark at rest. */
.experience-path--client {
  border-color: color-mix(in srgb, var(--brand, #1a5490) 30%, var(--border, #c5d8df));
}
.experience-path--client:is(:hover, :focus-visible) {
  background: color-mix(in srgb, var(--brand, #1a5490) 8%, var(--surface, #fbfdfd));
  border-color: var(--brand, #1a5490);
}
.experience-path--client:is(:hover, :focus-visible) .experience-label {
  color: var(--brand, #1a5490);
}
.experience-path--client:is(:hover, :focus-visible) .experience-label svg {
  color: var(--brand, #1a5490);
}
/* Notary path: accent purple on hover only — text stays dark at rest. */
.experience-path--notary {
  border-color: color-mix(in srgb, var(--accent-purple, #6b4c9a) 30%, var(--border, #c5d8df));
}
.experience-path--notary:is(:hover, :focus-visible) {
  background: color-mix(in srgb, var(--accent-purple, #6b4c9a) 8%, var(--surface, #fbfdfd));
  border-color: var(--accent-purple, #6b4c9a);
}
.experience-path--notary:is(:hover, :focus-visible) .experience-label {
  color: var(--accent-purple, #6b4c9a);
}
.experience-path--notary:is(:hover, :focus-visible) .experience-label svg {
  color: var(--accent-purple, #6b4c9a);
}
/* Generic hero-cta buttons (non-experience-paths) keep a strong outlined presence. */
.hero-cta > .btn { color: var(--action-ink); border: 2px solid var(--action-ink); background: transparent; font-weight: 700; font-size: 15px; min-height: 52px; height: auto; white-space: normal; text-align: center; padding: 12px 24px; transition: background var(--motion-fast), transform var(--motion-fast), box-shadow var(--motion-fast); }
.hero-cta > .btn:not(:disabled):is(:hover, :focus-visible) { background: var(--action-tint); transform: translateY(-2px); box-shadow: var(--shadow-sm); }
/* La rangée des agendas tient la place de la rangée d'action : même air au-dessus
   que .hero-cta. */
.calendar-subscription { width: 100%; margin-top: var(--space-10); }
.arrival-showcase { position: fixed; inset: 0; z-index: 45; pointer-events: none; }
#pane-carnet.is-active { animation-name: arrival-pane-in; }
@keyframes arrival-pane-in { from { opacity: 0; } to { opacity: 1; } }
.intro .experience-paths { animation-delay: 0s; }
.arrival-cursor {
  position: fixed; left: 0; top: 0; width: 20px; height: 26px;
  pointer-events: none; z-index: 1; color: var(--ink);
  transform: translate(var(--arrival-x), var(--arrival-y));
  transition: transform var(--arrival-travel) var(--ease-ui), opacity var(--motion-enter) var(--ease-ui);
  filter: drop-shadow(0 1px 2px var(--border));
  opacity: 0;
}
.arrival-cursor.is-visible { opacity: 1; }
.arrival-cursor svg { width: 100%; height: 100%; fill: var(--surface); stroke: currentColor; stroke-width: 1.5; stroke-linejoin: round; }
.experience-path.arrival-target {
  transform: scale(1.03); background: var(--action-tint-strong); box-shadow: var(--shadow-sm);
}
/* The replay link is a low-emphasis utility — styled as a ghost text action,
   not a button, so it never competes with the hero CTAs. */
.arrival-replay {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: var(--space-5); padding: 4px 0;
  background: none; border: 0; color: var(--ink-muted); font: inherit; font-size: 13px;
  cursor: pointer; opacity: 0.7; transition: opacity var(--motion-fast), color var(--motion-fast);
}
.arrival-replay:hover { opacity: 1; color: var(--action-ink); }
.arrival-replay::before { content: '↺'; font-size: 15px; }
@media (prefers-reduced-motion: reduce) {
  .arrival-cursor, .arrival-showcase { display: none; }
  .experience-path.arrival-target { transform: none; }
}
@media (max-width: 380px) {
  .experience-paths { gap: var(--space-4); }
  .experience-path { padding: 16px 18px; }
  .experience-label { font-size: 14px; gap: var(--space-2); }
  .experience-action { font-size: 13px; }
}
/* On phones the two paths stack vertically. */
@media (max-width: 520px) {
  .experience-paths { grid-template-columns: minmax(0, 1fr); gap: var(--space-6); }
}

/* Voice trigger buttons in each pane */
.pane-voice-trigger {
  margin-top: var(--space-8, 32px);
  padding-top: var(--space-6, 24px);
  border-top: 1px solid var(--border, #c5d8df);
}
.voice-inline-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2, 8px);
  padding: 10px 16px;
  border-radius: var(--radius);
  border: 1.5px solid var(--border, #c5d8df);
  background: transparent;
  color: var(--ink-muted, #526b78);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--motion-fast, 0.2s), border-color var(--motion-fast, 0.2s), color var(--motion-fast, 0.2s);
}
.voice-inline-btn:is(:hover, :focus-visible) {
  background: var(--brand-tint, rgba(26, 84, 144, 0.06));
  border-color: var(--brand, #1a5490);
  color: var(--brand, #1a5490);
}
.voice-inline-btn svg {
  flex: none;
  color: inherit;
}

#notary-live, #notary-open-list { scroll-margin-top: var(--sticky-top); }
.landing-copy > .hero-free { font-size: var(--type-h4); line-height: var(--type-body-lh); margin-top: var(--space-5); }
/* The pricing line is a reassurance, not fine print — give it a subtle
   left accent bar and slightly richer color so it reads at a glance. */
#pane-carnet .hero-free {
  border-left: 2px solid var(--brand-tint-solid-strong);
  padding-left: var(--space-5);
  color: var(--ink-muted);
  max-width: 52ch;
}
#pane-carnet .hero-free strong { color: var(--ink); }

/* Sign-up is also available within the shared sign-in sheet. */
@media (pointer: coarse) and (min-width: 900px) and (max-width: 999.98px) {
  #header-signup { display: none; }
}
/* The active guide owns the bottom corner; help remains alongside the page. */
body:has(.client-walk:not([hidden])) .speed-dial {
  position: relative; inset: auto; width: fit-content;
  margin: var(--space-4); margin-inline-start: auto;
}

/* ── Landing / Accueil pane ── */
.btn-outline {
  border-color: var(--border-strong, #a9c3ce);
  background: transparent;
  color: var(--ink, #173b52);
  font-weight: 600;
  transition: border-color var(--motion-fast), color var(--motion-fast), transform var(--motion-fast) var(--ease-ui);
}
.btn-outline:not(:disabled):is(:hover, :focus-visible) {
  border-color: var(--brand, #386888);
  color: var(--brand, #386888);
  transform: translateY(-1px);
}
.accueil-cta .btn-lg { padding: 14px 28px; font-size: 16px; }
.accueil-cta .btn { transition: transform var(--motion-ui) var(--ease-ui), box-shadow var(--motion-ui) var(--ease-ui), border-color var(--motion-ui) var(--ease-ui); }
.accueil-cta .btn:is(:hover, :focus-visible) { transform: translateY(-2px) scale(1.02); }

/* ── Hero ─────────────────────────────────────────────────────────── */
.accueil-hero {
  min-height: calc(100vh - var(--header-h, 64px));
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 60px var(--layout-gutter, 24px) 80px;
  position: relative;
  overflow: hidden;
}
/* Two soft radial glows give the hero depth without a background image.
   The brand tint sits low-centre; a cooler secondary glow lifts the top. */
.accueil-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 70% 50% at 50% 80%, color-mix(in srgb, var(--brand, #386888) 8%, transparent) 0%, transparent 70%),
    radial-gradient(ellipse 50% 40% at 30% 10%, color-mix(in srgb, var(--brand, #386888) 4%, transparent) 0%, transparent 60%);
  pointer-events: none;
}
/* A faint dot grid adds texture — visible on close inspection, invisible at a glance. */
.accueil-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image: radial-gradient(color-mix(in srgb, var(--ink, #173b52) 8%, transparent) 1px, transparent 1px);
  background-size: 24px 24px;
  opacity: .35;
  pointer-events: none;
  mask-image: radial-gradient(ellipse 60% 50% at 50% 50%, black 20%, transparent 70%);
  -webkit-mask-image: radial-gradient(ellipse 60% 50% at 50% 50%, black 20%, transparent 70%);
}
.accueil-hero-inner {
  position: relative;
  max-width: 720px;
}
.accueil-lockup {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-bottom: 36px;
  animation: accueil-hero-fade-in var(--motion-enter) var(--ease-ui) 0.1s forwards;
}
.accueil-lockup .brand-mark-svg { height: var(--lockup-tile, 52px); width: var(--lockup-tile, 52px); }
.accueil-word-svg { height: 26px; width: auto; color: var(--ink, #173b52); }
.accueil-title {
  color: var(--ink, #173b52);
  line-height: 1.08;
  animation: accueil-hero-fade-in var(--motion-enter) var(--ease-ui) 0.2s forwards;
}
.accueil-hero { --type-h1: clamp(32px, 5.5vw, 60px); }
.accueil-title .accent {
  display: inline;
  background: linear-gradient(135deg, var(--brand, #386888) 0%, color-mix(in srgb, var(--brand, #386888) 70%, #2a9d8f) 50%, var(--brand, #386888) 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  background-size: 200% 200%;
  animation: accueil-gradient-shift 8s ease infinite;
}
@keyframes accueil-gradient-shift {
  0%, 100% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
}
.accueil-lede {
  margin-top: 24px;
  font-size: clamp(16px, 2.2vw, 20px);
  color: var(--ink-muted, #526b78);
  line-height: 1.6;
  max-width: 520px;
  margin-inline: auto;
  animation: accueil-hero-fade-in var(--motion-enter) var(--ease-ui) 0.3s forwards;
}
.accueil-cta {
  margin-top: 40px;
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  justify-content: center;
  animation: accueil-hero-fade-in var(--motion-enter) var(--ease-ui) 0.4s forwards;
}
@keyframes accueil-hero-fade-in {
  0% { opacity: 0; transform: translateY(20px); }
  100% { opacity: 1; transform: translateY(0); }
}

/* ── Dividers & sections ──────────────────────────────────────────── */
.accueil-divider { padding: 0 var(--layout-gutter, 24px); }
.accueil-divider hr {
  border: none;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--border, #c5d8df) 30%, var(--border, #c5d8df) 70%, transparent);
  margin: 0;
}

.accueil-section {
  padding: 100px var(--layout-gutter, 24px);
  max-width: var(--layout-width, 1200px);
  margin: 0 auto;
}
.accueil-section--alt {
  position: relative;
  background: linear-gradient(180deg, var(--surface, #fbfdfd), color-mix(in srgb, var(--surface, #fbfdfd) 92%, var(--brand, #386888)));
  border: 1px solid color-mix(in srgb, var(--border, #c5d8df) 60%, transparent);
  border-radius: var(--radius-lg);
  margin: 0 clamp(16px, 4vw, 40px);
  max-width: calc(var(--layout-width, 1200px) - 2 * clamp(16px, 4vw, 40px));
}
.accueil-section-head { --type-h2: clamp(24px, 3.5vw, 38px); max-width: 600px; }
.accueil-section-head .eyebrow {
  display: inline-block;
  padding: 4px 10px;
  border: 1px solid color-mix(in srgb, var(--ink-muted, #526b78) 25%, transparent);
  border-radius: var(--radius-lg);
  color: var(--subtitle-ink, var(--ink));
  margin-bottom: 12px;
}
.accueil-section-head h2 {
  color: var(--ink, #173b52);
  line-height: 1.12;
}
.accueil-section-head p {
  margin-top: 16px;
  font-size: 17px;
  color: var(--ink-muted, #526b78);
  line-height: 1.6;
}
.accueil-section-head--center {
  text-align: center;
  margin-inline: auto;
}

/* ── Value cards ──────────────────────────────────────────────────── */
.valeur-grid {
  margin-top: 56px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 20px;
}
.valeur-card {
  position: relative;
  border: 1px solid var(--border, #c5d8df);
  border-radius: var(--radius-lg);
  padding: 32px 28px;
  transition: border-color var(--motion-ui) var(--ease-ui), transform var(--motion-ui) var(--ease-ui), box-shadow var(--motion-ui) var(--ease-ui);
  background: var(--surface, #fbfdfd);
}
.valeur-card:is(:hover, :focus-within) {
  border-color: var(--brand, #386888);
  transform: translateY(-3px);
  box-shadow: 0 12px 32px -8px color-mix(in srgb, var(--brand, #386888) 15%, transparent);
}
.valeur-icon {
  width: 48px; height: 48px;
  border: 1.5px solid color-mix(in srgb, var(--brand, #386888) 30%, var(--border, #c5d8df));
  border-radius: var(--radius-lg);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 20px;
  color: var(--brand, #386888);
  background: color-mix(in srgb, var(--brand, #386888) 5%, transparent);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--brand, #386888) 0%, transparent);
  transition: box-shadow var(--motion-ui) var(--ease-ui), border-color var(--motion-ui) var(--ease-ui);
}
.valeur-card:is(:hover, :focus-within) .valeur-icon {
  box-shadow: 0 4px 16px -4px color-mix(in srgb, var(--brand, #386888) 25%, transparent);
  border-color: var(--brand, #386888);
}
.valeur-card h3 {
  color: var(--ink, #173b52);
  margin-bottom: 8px;
}
.valeur-card p {
  font-size: 15px;
  color: var(--ink-muted, #526b78);
  line-height: 1.65;
}

/* ── Steps ────────────────────────────────────────────────────────── */
.etape-grid {
  margin-top: 56px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 40px;
  counter-reset: etape;
  position: relative;
}
/* A connecting line between steps on wide screens */
.etape-grid::before {
  content: '';
  position: absolute;
  top: 20px;
  left: calc(16.66% + 20px);
  right: calc(16.66% + 20px);
  height: 2px;
  background: linear-gradient(90deg, var(--brand, #386888), color-mix(in srgb, var(--brand, #386888) 40%, #2a9d8f), var(--brand, #386888));
  opacity: .4;
}
@media (max-width: 768px) {
  .etape-grid::before { display: none; }
}
.etape {
  counter-increment: etape;
  position: relative;
  padding-left: 0;
  text-align: center;
}
.etape-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 2px solid var(--brand, #386888);
  font-family: var(--font-display, 'Sora', system-ui, sans-serif);
  font-weight: 800;
  font-size: 16px;
  color: var(--brand, #386888);
  background: var(--surface, #fbfdfd);
  margin-bottom: 18px;
  position: relative;
  z-index: 1;
  transition: box-shadow var(--motion-ui) var(--ease-ui), transform var(--motion-ui) var(--ease-ui);
}
.etape:is(:hover, :focus-within) .etape-num {
  box-shadow: 0 4px 16px -4px color-mix(in srgb, var(--brand, #386888) 30%, transparent);
  transform: scale(1.05);
}
.etape h3 {
  color: var(--ink, #173b52);
  margin-bottom: 8px;
}
.etape p {
  font-size: 15px;
  color: var(--ink-muted, #526b78);
  line-height: 1.65;
  max-width: 280px;
  margin-inline: auto;
}

/* ── Stats ────────────────────────────────────────────────────────── */
.stat-grid {
  margin-top: 56px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 20px;
}
.stat-card {
  border: 1px solid var(--border, #c5d8df);
  border-radius: var(--radius-lg);
  padding: 32px 20px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  background: var(--surface, #fbfdfd);
  transition: border-color var(--motion-ui) var(--ease-ui), transform var(--motion-ui) var(--ease-ui), box-shadow var(--motion-ui) var(--ease-ui);
}
.stat-card:is(:hover, :focus-within) {
  border-color: var(--brand, #386888);
  transform: translateY(-4px);
  box-shadow: 0 12px 32px -8px color-mix(in srgb, var(--brand, #386888) 18%, transparent);
}
.stat-number {
  font-family: var(--font-display, 'Sora', system-ui, sans-serif);
  font-weight: 800;
  font-size: clamp(36px, 4.5vw, 52px);
  background: linear-gradient(135deg, var(--brand, #386888) 0%, color-mix(in srgb, var(--brand, #386888) 60%, #2a9d8f) 50%, var(--brand, #386888) 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  line-height: 1.1;
  letter-spacing: -0.02em;
}
.stat-label {
  margin-top: 10px;
  font-size: 14px;
  color: var(--ink-muted, #526b78);
  font-weight: 500;
}

/* ── Final CTA ────────────────────────────────────────────────────── */
.accueil-cta-section {
  padding: 120px var(--layout-gutter, 24px);
  text-align: center;
  position: relative;
}
.accueil-cta-section::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 60% 60% at 50% 50%, color-mix(in srgb, var(--brand, #386888) 5%, transparent) 0%, transparent 70%);
  pointer-events: none;
}

/* ── Scroll reveal ────────────────────────────────────────────────── */
.accueil-reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity var(--motion-enter) var(--ease-ui), transform var(--motion-enter) var(--ease-ui);
}
.accueil-reveal.visible {
  opacity: 1;
  transform: translateY(0);
}
/* Staggered delays for child elements within revealed sections */
.accueil-reveal.visible .valeur-card:nth-child(1) { animation: accueil-fade-up var(--motion-enter) var(--ease-ui) 0.1s both; }
.accueil-reveal.visible .valeur-card:nth-child(2) { animation: accueil-fade-up var(--motion-enter) var(--ease-ui) 0.2s both; }
.accueil-reveal.visible .valeur-card:nth-child(3) { animation: accueil-fade-up var(--motion-enter) var(--ease-ui) 0.3s both; }
.accueil-reveal.visible .etape:nth-child(1) { animation: accueil-fade-up var(--motion-enter) var(--ease-ui) 0.1s both; }
.accueil-reveal.visible .etape:nth-child(2) { animation: accueil-fade-up var(--motion-enter) var(--ease-ui) 0.2s both; }
.accueil-reveal.visible .etape:nth-child(3) { animation: accueil-fade-up var(--motion-enter) var(--ease-ui) 0.3s both; }
.accueil-reveal.visible .stat-card:nth-child(1) { animation: accueil-fade-up var(--motion-enter) var(--ease-ui) 0.1s both; }
.accueil-reveal.visible .stat-card:nth-child(2) { animation: accueil-fade-up var(--motion-enter) var(--ease-ui) 0.15s both; }
.accueil-reveal.visible .stat-card:nth-child(3) { animation: accueil-fade-up var(--motion-enter) var(--ease-ui) 0.2s both; }
.accueil-reveal.visible .stat-card:nth-child(4) { animation: accueil-fade-up var(--motion-enter) var(--ease-ui) 0.25s both; }
@keyframes accueil-fade-up {
  0% { opacity: 0; transform: translateY(16px); }
  100% { opacity: 1; transform: translateY(0); }
}

/* ── Dark theme overrides ─────────────────────────────────────────── */
[data-theme="dark"] .accueil-word-svg { color: var(--ink, #f4f8fa); }
[data-theme="dark"] .accueil-hero::before {
  background:
    radial-gradient(ellipse 70% 50% at 50% 80%, color-mix(in srgb, var(--brand, #386888) 12%, transparent) 0%, transparent 70%),
    radial-gradient(ellipse 50% 40% at 30% 10%, color-mix(in srgb, var(--brand, #386888) 6%, transparent) 0%, transparent 60%);
}
[data-theme="dark"] .accueil-hero::after { opacity: .15; }
[data-theme="dark"] .valeur-card,
[data-theme="dark"] .stat-card { background: var(--surface-elevated, var(--surface, #1e2a34)); }
[data-theme="dark"] .etape-num { background: var(--surface, #1a242e); }
[data-theme="dark"] .accueil-section--alt {
  background: linear-gradient(180deg, var(--surface-elevated, #1e2a34), color-mix(in srgb, var(--surface-elevated, #1e2a34) 90%, var(--brand, #386888)));
  border-color: color-mix(in srgb, var(--brand, #386888) 20%, transparent);
}
[data-theme="dark"] .accueil-title { color: var(--ink, #f4f8fa); }
[data-theme="dark"] .accueil-section-head h2 { color: var(--ink, #f4f8fa); }
[data-theme="dark"] .valeur-card h3 { color: var(--ink, #f4f8fa); }
[data-theme="dark"] .etape h3 { color: var(--ink, #f4f8fa); }
[data-theme="dark"] .btn-outline { color: var(--ink, #f4f8fa); border-color: var(--border-strong, #536273); }
[data-theme="dark"] .btn-outline:is(:hover, :focus-visible) { color: var(--brand-bright, #78a9bf); border-color: var(--brand-bright, #78a9bf); }
