:root {
    color-scheme: dark;
    --bg: #020611;
    --main: #050a14;
    --sidebar: #030812;
    --sidebar-hover: #0b1320;
    --sidebar-active: #101b2c;
    --panel: #0a111d;
    --panel-2: #0d1726;
    --line: rgba(142, 171, 211, 0.14);
    --line-strong: rgba(62, 137, 255, 0.30);
    --text: #f6f8fc;
    --muted: #8b99ae;
    --subtle: #66748a;
    --blue: #2f7fff;
    --blue-2: #155ee9;
    --blue-soft: rgba(47, 127, 255, 0.13);
    --danger: #ff707d;
    --shadow: 0 28px 80px rgba(0, 0, 0, 0.52);
    --safe-top: env(safe-area-inset-top, 0px);
    --safe-right: env(safe-area-inset-right, 0px);
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    --safe-left: env(safe-area-inset-left, 0px);
}

* {
    box-sizing: border-box;
}

html,
body {
    width: 100%;
    height: 100%;
    margin: 0;
}

body {
    overflow: hidden;
    background:
        radial-gradient(circle at 70% 10%, rgba(24, 79, 180, 0.13), transparent 42%),
        linear-gradient(145deg, #02040a, #020813 55%, #02040a);
    color: var(--text);
    font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

button,
input,
textarea {
    font: inherit;
}

button {
    color: inherit;
}

button,
textarea,
input {
    outline: none;
}

svg {
    width: 20px;
    height: 20px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* AUTH */

/* Ecran d'authentification.

   `min-height: 510px` combine a `inset: 0` et `margin: auto` produisait un
   blocage total en paysage, et le detail du calcul compte. Avec `top: 0`,
   `bottom: 0` et une hauteur automatique, une boite positionnee resout sa
   hauteur a celle du viewport et ses marges automatiques valent 0. Mais des
   que `min-height` depasse cette hauteur — 510px pour environ 342px de
   viewport paysage — la hauteur est re-resolue a 510px : les trois valeurs
   deviennent non automatiques, et les marges automatiques se partagent alors
   le deficit A PARTS EGALES. La carte debordait donc AU-DESSUS autant qu'en
   dessous du viewport, en `position: fixed`, dans un document que
   `body { overflow: hidden }` empeche de defiler. Aucun defilement n'etait
   possible, par construction — ni du document, ni de la carte.

   `height: 100svh` la borne au plus petit viewport, comme C3 et C8 l'ont
   valide sur appareil reel, avec `100%` en repli pour les moteurs sans `svh`.
   `bottom: auto` l'ancre en haut : la laisser centree dans le viewport LARGE
   maintiendrait son bas sous la barre Safari. Sur bureau la hauteur resolue
   etait deja celle du viewport et `min-height` ne mordait jamais : la mise en
   page y est rigoureusement identique.

   `overflow-y: auto` rend la carte defilante quand son contenu la depasse, et
   reste sans effet visible sinon — le portrait ne bouge pas.

   `safe center` n'est pas cosmetique. Un `center` simple centre aussi le
   debordement, or la region defilante ne s'etend jamais avant le bord de
   depart : le haut du formulaire serait devenu definitivement inatteignable,
   et le correctif n'aurait repare que la moitie du probleme. `safe` bascule
   sur un alignement en haut des que le contenu deborde. La declaration
   `center` est conservee juste au-dessus comme repli. */
.auth-screen {
    width: min(430px, calc(100% - 34px));
    height: 100%;
    height: 100svh;
    padding: 34px;
    position: fixed;
    inset: 0 0 auto 0;
    margin: auto;
    display: flex;
    flex-direction: column;
    justify-content: center;
    justify-content: safe center;
    overflow-y: auto;
    gap: 20px;
    background: rgba(4, 10, 20, 0.91);
    border: 1px solid var(--line-strong);
    border-radius: 24px;
    box-shadow: var(--shadow), 0 0 60px rgba(31, 105, 255, 0.13);
    backdrop-filter: blur(22px);
}

.auth-brand {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    color: white;
    font-weight: 850;
    letter-spacing: .18em;
}

.auth-screen h1 {
    margin: 8px 0 -10px;
    text-align: center;
    font-size: 1.9rem;
}

.auth-screen > p {
    margin: 0;
    text-align: center;
    color: var(--muted);
}

.auth-tabs {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 5px;
    padding: 5px;
    background: rgba(255, 255, 255, 0.035);
    border: 1px solid var(--line);
    border-radius: 12px;
}

.auth-tab {
    padding: 10px;
    border: 0;
    border-radius: 9px;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
}

.auth-tab.active {
    background: var(--panel-2);
    color: var(--text);
}

#auth-form {
    display: flex;
    flex-direction: column;
    gap: 15px;
}

#auth-form label {
    display: flex;
    flex-direction: column;
    gap: 7px;
    color: #c3ccda;
    font-size: .88rem;
}

#auth-form input {
    width: 100%;
    padding: 13px 14px;
    border: 1px solid var(--line);
    border-radius: 11px;
    background: rgba(1, 6, 14, .8);
    color: var(--text);
}

#auth-form input:focus {
    border-color: rgba(47, 127, 255, .75);
    box-shadow: 0 0 0 4px rgba(47, 127, 255, .10);
}

.auth-submit {
    min-height: 46px;
    border: 0;
    border-radius: 11px;
    background: linear-gradient(135deg, #458fff, #1f67ec);
    color: white;
    font-weight: 780;
    cursor: pointer;
}

.auth-submit:disabled {
    opacity: .55;
}

.auth-error {
    min-height: 20px;
    color: var(--danger) !important;
    font-size: .87rem;
}

/* APP */

/* Hauteur au repos : `svh`. Sur Safari iOS, `100%` se résout sur le viewport
   large, donc le bas de l'application passe sous la barre d'outils tant que
   celle-ci est déployée ; `svh` borne l'application au plus petit viewport et
   cadre correctement au chargement. */
/* `grid-template-rows` explicite : sans lui, la grille n'avait qu'une ligne
   IMPLICITE dimensionnée `auto`. Une piste `auto` se calcule sur le contenu et
   n'est jamais bornée par la hauteur du conteneur — la hauteur définie de
   `.app-shell` ne s'imposait donc pas à la ligne.

   `.main-panel` échappait au problème parce que son `overflow: hidden` en fait
   un conteneur de défilement : son contenu ne participe pas à sa taille
   intrinsèque, il ne pousse pas la piste. `.sidebar` est en `overflow: visible`
   et lui poussait la piste à sa hauteur de contenu.

   Conséquence mesurée sur Firefox, 5 conversations, fenêtre 1280 x 500 : piste
   et sidebar à 547px pour un viewport de 500px, `.conversation-list` étirée à
   235/235 donc SANS défilement possible, et `.sidebar-bottom` hors écran. Le
   débordement était absorbé par `body { overflow: hidden }`, d'où l'absence
   totale de barre de défilement. En fenêtre haute la même page mesurait
   900/900 et fonctionnait : le seuil n'est pas la fenêtre en soi, c'est la
   hauteur de contenu de la sidebar comparée à celle du viewport.

   `minmax(0, 1fr)` fixe la ligne à la hauteur du conteneur. La sidebar cesse de
   grandir, `.conversation-list` retrouve le reliquat qu'elle sait déjà faire
   défiler avec ses `flex: 1`, `min-height: 0` et `overflow-y: auto`.

   Aucun effet en mode téléphone : la sidebar y est `position: fixed`, donc hors
   grille, et `.main-panel` reste seul dans la ligne — déjà étiré à la hauteur
   du conteneur auparavant, puisqu'il n'y contribuait pas. */
.app-shell {
    width: 100%;
    height: 100%;
    height: 100svh;
    display: grid;
    grid-template-columns: 324px minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
    background: var(--main);
}

/* Hauteur pendant le focus du composeur : retour à `100%`. Mesuré sur appareil
   réel (iPhone 15 / iOS 26.5.2 / Safari privé) : `100dvh` comme `100svh` font
   échouer le PREMIER appui sur le composeur, `100%` le fait réussir. Les deux
   unités détachent le bas de `.app-shell` — donc celui de `.composer-zone`, qui
   y est ancrée en absolu — du bloc de contenu initial sur lequel Safari calcule
   son défilement « amener le champ focalisé à l'écran » : ce défilement tombe
   court et le composeur reste sous le clavier. `100%` restitue exactement la
   géométrie du seul état validé au clavier.

   Le sélecteur ne vise que le champ de saisie : la recherche d'historique et
   les boutons du composeur (+, micro, envoyer) prennent le focus sans ouvrir le
   clavier et ne doivent pas changer la hauteur. */
.app-shell:has(#user-input:focus) {
    height: 100%;
}

.sidebar {
    min-width: 0;
    position: relative;
    z-index: 20;
    display: flex;
    flex-direction: column;
    padding: calc(18px + var(--safe-top)) 14px calc(12px + var(--safe-bottom)) calc(14px + var(--safe-left));
    background:
        linear-gradient(180deg, rgba(23, 64, 133, .10), transparent 26%),
        var(--sidebar);
    border-right: 1px solid var(--line);
    transition: width .18s ease, transform .18s ease;
}

.sidebar-top {
    min-height: 45px;
    padding: 0 8px;
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.sidebar-brand {
    display: flex;
    align-items: center;
    gap: 11px;
    font-weight: 860;
    letter-spacing: .16em;
}

.ghost-icon-button {
    width: 38px;
    height: 38px;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: 10px;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
}

.ghost-icon-button:hover {
    background: rgba(255,255,255,.05);
    color: white;
}

.new-chat-button {
    width: 100%;
    min-height: 49px;
    margin: 18px 0 28px;
    padding: 0 16px;
    display: flex;
    align-items: center;
    gap: 12px;
    border: 0;
    border-radius: 13px;
    background: linear-gradient(135deg, #2f7fff, #1e66ef);
    color: white;
    font-weight: 720;
    cursor: pointer;
    box-shadow: 0 10px 26px rgba(24, 93, 224, .24);
}

.new-chat-button:hover {
    filter: brightness(1.07);
}

.sidebar-section-label {
    padding: 0 10px 10px;
    color: #68778c;
    font-size: .74rem;
    font-weight: 760;
    letter-spacing: .09em;
    text-transform: uppercase;
}

.conversation-list {
    min-height: 0;
    flex: 1;
    overflow-y: auto;
    padding-right: 3px;
}

.conversation-list::-webkit-scrollbar,
.chat-window::-webkit-scrollbar {
    width: 6px;
}

.conversation-list::-webkit-scrollbar-thumb,
.chat-window::-webkit-scrollbar-thumb {
    background: rgba(118, 143, 178, .20);
    border-radius: 999px;
}

.conversation-row {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 34px;
    align-items: center;
    margin-bottom: 4px;
    border-radius: 10px;
}

.conversation-row:hover,
.conversation-row.active {
    background: var(--sidebar-hover);
}

.conversation-row.active {
    background: var(--sidebar-active);
}

.conversation-open {
    min-width: 0;
    min-height: 43px;
    padding: 0 5px 0 9px;
    display: flex;
    align-items: center;
    gap: 10px;
    border: 0;
    background: transparent;
    color: #d7deea;
    cursor: pointer;
}

.conversation-open svg {
    width: 17px;
    height: 17px;
    flex: 0 0 auto;
    color: #8593a7;
}

.conversation-open span {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    text-align: left;
    font-size: .89rem;
}

.conversation-more {
    width: 30px;
    height: 30px;
    margin-right: 3px;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: #8390a3;
    cursor: pointer;
    opacity: 0;
}

.conversation-row:hover .conversation-more,
.conversation-row.active .conversation-more,
.conversation-more:focus-visible {
    opacity: 1;
}

.conversation-more:hover {
    background: rgba(255,255,255,.06);
}

.conversation-menu {
    width: 145px;
    padding: 6px;
    position: absolute;
    right: 7px;
    top: 37px;
    z-index: 35;
    display: none;
    background: #101827;
    border: 1px solid var(--line-strong);
    border-radius: 10px;
    box-shadow: 0 18px 44px rgba(0,0,0,.48);
}

.conversation-menu.open {
    display: flex;
    flex-direction: column;
}

.conversation-menu button {
    padding: 9px 10px;
    border: 0;
    border-radius: 7px;
    background: transparent;
    text-align: left;
    cursor: pointer;
}

.conversation-menu button:hover {
    background: rgba(255,255,255,.06);
}

.conversation-menu .delete-item {
    color: var(--danger);
}

.history-empty {
    padding: 20px 12px;
    color: #5e6d82;
    text-align: center;
    font-size: .82rem;
}

.history-empty[hidden] {
    display: none;
}

.sidebar-bottom {
    position: relative;
    padding-top: 11px;
    border-top: 1px solid var(--line);
}

.profile-trigger {
    width: 100%;
    min-height: 58px;
    padding: 8px 9px;
    display: grid;
    grid-template-columns: 38px minmax(0, 1fr) 22px;
    align-items: center;
    gap: 10px;
    border: 0;
    border-radius: 12px;
    background: transparent;
    cursor: pointer;
}

.profile-trigger:hover {
    background: rgba(255,255,255,.045);
}

.profile-avatar {
    width: 38px;
    height: 38px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: linear-gradient(145deg, #2f7fff, #0c4fd2);
    color: white;
    font-size: .78rem;
    font-weight: 820;
    box-shadow: 0 0 0 3px rgba(47, 127, 255, .08);
}

.profile-copy,
.profile-menu-copy {
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
}

.profile-copy strong,
.profile-menu-copy strong,
.profile-copy small,
.profile-menu-copy small {
    max-width: 100%;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.profile-copy strong,
.profile-menu-copy strong {
    font-size: .9rem;
}

.profile-copy small,
.profile-menu-copy small {
    margin-top: 2px;
    color: var(--muted);
    font-size: .74rem;
}

.profile-chevron {
    width: 17px;
    height: 17px;
    color: #7d8ca0;
}

.profile-menu {
    width: calc(100% - 2px);
    padding: 9px;
    position: absolute;
    left: 1px;
    bottom: 68px;
    z-index: 50;
    background: #111927;
    border: 1px solid var(--line-strong);
    border-radius: 16px;
    box-shadow: 0 24px 60px rgba(0,0,0,.52);
}

.profile-menu[hidden] {
    display: none;
}

.profile-menu-head {
    padding: 7px;
    display: grid;
    grid-template-columns: 38px minmax(0,1fr);
    gap: 10px;
    align-items: center;
}

.profile-menu-separator {
    height: 1px;
    margin: 8px 5px;
    background: var(--line);
}

.profile-menu > button {
    width: 100%;
    min-height: 42px;
    padding: 0 10px;
    display: flex;
    align-items: center;
    gap: 11px;
    border: 0;
    border-radius: 9px;
    background: transparent;
    color: #dce4ef;
    cursor: pointer;
}

.profile-menu > button:hover {
    background: rgba(255,255,255,.055);
}

.profile-menu > button svg {
    width: 18px;
    height: 18px;
    color: #99a8bc;
}

.profile-menu .danger-menu-item {
    color: var(--danger);
}

/* MAIN */

.main-panel {
    min-width: 0;
    position: relative;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background:
        radial-gradient(circle at 55% 36%, rgba(19, 70, 156, .15), transparent 28%),
        radial-gradient(circle at 92% 6%, rgba(20, 56, 115, .09), transparent 32%),
        var(--main);
}

.mobile-menu-button {
    width: 42px;
    height: 42px;
    position: absolute;
    z-index: 10;
    top: calc(16px + var(--safe-top));
    left: calc(16px + var(--safe-left));
    display: none;
    place-items: center;
    border: 1px solid var(--line);
    border-radius: 11px;
    background: rgba(7, 14, 25, .78);
    color: var(--muted);
}

.chat-window {
    width: 100%;
    max-width: 1080px;
    min-height: 0;
    flex: 1;
    align-self: center;
    overflow-y: auto;
    padding: 36px 42px 190px;
}

.welcome-state {
    min-height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    transform: translateY(-18px);
    text-align: center;
}

.jarvis-mark {
    display: grid;
    place-items: center;
    border: 1px solid rgba(47, 127, 255, .72);
    color: #377fff;
    font-weight: 880;
    background:
        linear-gradient(145deg, rgba(24, 80, 192, .22), rgba(1, 7, 16, .8));
    box-shadow:
        inset 0 0 0 1px rgba(77, 142, 255, .09),
        0 0 28px rgba(31, 105, 255, .18);
}

.hero-mark {
    width: 82px;
    height: 82px;
    margin-bottom: 30px;
    border-radius: 25px;
    font-size: 2rem;
    clip-path: polygon(50% 0, 92% 24%, 92% 76%, 50% 100%, 8% 76%, 8% 24%);
}

.small-mark {
    width: 34px;
    height: 34px;
    border-radius: 11px;
}

.mini-mark {
    width: 31px;
    height: 31px;
    border-radius: 10px;
    font-size: .82rem;
}

.welcome-state h1 {
    margin: 0;
    color: #f1f4fa;
    font-size: clamp(2rem, 4vw, 3rem);
    font-weight: 720;
    letter-spacing: -.035em;
}

.welcome-state h1 span {
    color: #397fff;
}

.welcome-line {
    width: 48px;
    height: 2px;
    margin: 30px 0 20px;
    border-radius: 99px;
    background: linear-gradient(90deg, transparent, #327cff, transparent);
    box-shadow: 0 0 12px rgba(50, 124, 255, .55);
}

.welcome-state p {
    margin: 0;
    color: var(--muted);
    font-size: 1rem;
}

.message-row {
    width: 100%;
    margin-bottom: 26px;
    display: flex;
    gap: 13px;
    align-items: flex-start;
    animation: message-in .18s ease-out;
}

.message-row.user {
    justify-content: flex-end;
}

.message-avatar {
    width: 32px;
    height: 32px;
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    border-radius: 9px;
    background: #101a2a;
    border: 1px solid var(--line-strong);
    color: #6aa7ff;
    font-size: .74rem;
    font-weight: 820;
}

.message-row.user .message-avatar {
    background: #193d73;
    color: #d7e7ff;
}

.message-bubble {
    max-width: min(760px, 82%);
    padding: 7px 1px;
    color: #e7edf6;
    font-size: .98rem;
    line-height: 1.72;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.message-row.user .message-bubble {
    padding: 11px 15px;
    border-radius: 16px 5px 16px 16px;
    background: linear-gradient(135deg, #2d7dde, #1f60af);
    color: white;
    box-shadow: 0 10px 28px rgba(13, 68, 130, .18);
}

.typing-indicator {
    width: min(100%, 1080px);
    margin: -160px auto 104px;
    padding: 0 42px;
    position: relative;
    z-index: 2;
    display: flex;
    gap: 12px;
    align-items: center;
}

.typing-indicator[hidden] {
    display: none;
}

.typing-avatar {
    width: 32px;
    height: 32px;
    display: grid;
    place-items: center;
    border: 1px solid var(--line-strong);
    border-radius: 9px;
    color: #6aa7ff;
    font-size: .74rem;
    font-weight: 820;
}

.typing-bubble {
    display: flex;
    align-items: center;
    gap: 5px;
    color: var(--muted);
}

.typing-bubble span {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #4c91ff;
    animation: typing 1.2s infinite ease-in-out;
}

.typing-bubble span:nth-child(2) { animation-delay: .15s; }
.typing-bubble span:nth-child(3) { animation-delay: .3s; }

.typing-bubble small {
    margin-left: 5px;
}

.composer-zone {
    width: 100%;
    padding: 0 calc(28px + var(--safe-right)) calc(22px + var(--safe-bottom)) calc(28px + var(--safe-left));
    position: absolute;
    z-index: 5;
    left: 0;
    bottom: 0;
    background: linear-gradient(180deg, transparent, rgba(5,10,20,.95) 34%, var(--main) 72%);
}

.composer {
    width: min(100%, 1000px);
    min-height: 68px;
    margin: 0 auto;
    padding: 9px 10px 9px 13px;
    display: flex;
    align-items: flex-end;
    gap: 10px;
    border: 1px solid rgba(61, 126, 224, .40);
    border-radius: 28px;
    background: rgba(9, 17, 30, .94);
    box-shadow:
        0 18px 55px rgba(0,0,0,.38),
        0 0 0 1px rgba(38, 108, 230, .04);
    backdrop-filter: blur(20px);
}

.composer:focus-within {
    border-color: rgba(57, 127, 255, .72);
    box-shadow:
        0 18px 55px rgba(0,0,0,.38),
        0 0 0 4px rgba(47, 127, 255, .07);
}

.composer-icon-button,
.send-button {
    width: 46px;
    height: 46px;
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: 50%;
    cursor: pointer;
}

.composer-icon-button {
    background: rgba(255,255,255,.055);
    color: #9aa8ba;
}

.composer-icon-button:hover {
    background: rgba(255,255,255,.09);
    color: white;
}

#user-input {
    min-width: 0;
    min-height: 45px;
    max-height: 180px;
    flex: 1;
    resize: none;
    overflow-y: auto;
    padding: 11px 3px 7px;
    border: 0;
    background: transparent;
    color: var(--text);
    font-size: .99rem;
    line-height: 1.48;
}

#user-input::placeholder {
    color: #69778c;
}

.send-button {
    background: linear-gradient(145deg, #3f8cff, #2365ed);
    color: white;
    box-shadow: 0 8px 20px rgba(32, 98, 235, .28);
}

.send-button:disabled {
    opacity: .45;
}

.disclaimer {
    margin: 11px 0 0;
    color: #5d697a;
    text-align: center;
    font-size: .72rem;
}

/* MODAL */

.modal-backdrop {
    position: fixed;
    z-index: 100;
    inset: 0;
    display: grid;
    place-items: center;
    padding: 20px;
    background: rgba(0, 3, 8, .72);
    backdrop-filter: blur(8px);
}

.modal-backdrop[hidden] {
    display: none;
}

.modal-card {
    width: min(480px, 100%);
    overflow: hidden;
    background: #0b1422;
    border: 1px solid var(--line-strong);
    border-radius: 19px;
    box-shadow: var(--shadow);
}

.modal-head {
    padding: 18px 20px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid var(--line);
}

.modal-head small {
    color: var(--subtle);
    font-size: .68rem;
    letter-spacing: .12em;
}

.modal-head h2 {
    margin: 3px 0 0;
}

.modal-content {
    padding: 42px 30px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 15px;
    color: var(--muted);
    text-align: center;
    line-height: 1.6;
}

.settings-placeholder-icon {
    width: 58px;
    height: 58px;
    display: grid;
    place-items: center;
    border-radius: 16px;
    background: var(--blue-soft);
    color: #6ca7ff;
    font-size: 1.5rem;
}

.mobile-sidebar-backdrop {
    display: none;
}

@keyframes typing {
    0%, 80%, 100% { opacity: .32; transform: translateY(0); }
    40% { opacity: 1; transform: translateY(-4px); }
}

@keyframes message-in {
    from { opacity: 0; transform: translateY(5px); }
    to { opacity: 1; transform: translateY(0); }
}

/* COLLAPSED DESKTOP */

@media (min-width: 821px) {
    /* Ce bloc n'est pas reserve au bureau : un iPhone 15 couche mesure 852px de
       large et le recoit donc entierement, rail compact inclus. C'est l'etat
       decrit sur appareil reel — sidebar « fermee », rail sur le bord gauche.

       Le `padding-left: 10px` ci-dessous ECRASAIT le
       `calc(14px + var(--safe-left))` de `.sidebar`. En paysage, l'encoche vaut
       59px d'inset : le contenu du rail se retrouvait a 10px du bord physique,
       dans la zone d'exclusion systeme ou flottent les commandes Safari.
       Ce n'est donc pas une safe-area absente, c'est une safe-area annulee par
       une regle plus specifique.

       `--safe-left` suffit aux DEUX paysages : il vaut 59px quand l'encoche est
       a gauche et 0 quand elle est a droite, ou le bord est plat et ou aucun
       decalage n'est requis. Aucune valeur devinee de l'UI Safari n'est
       introduite : 78px et 10px sont les dimensions internes de Jarvis, seul
       l'inset systeme s'y ajoute.

       La piste s'elargit d'autant, sinon les 59px de padding mangeraient le
       rail. Le contenu conserve ainsi exactement ses 58px utiles. Sur bureau
       `--safe-left` vaut 0px : `calc(78px + 0px)` = 78px, mise en page
       rigoureusement identique. */
    .app-shell.sidebar-collapsed {
        grid-template-columns: calc(78px + var(--safe-left)) minmax(0, 1fr);
    }

    .app-shell.sidebar-collapsed .sidebar {
        padding-left: calc(10px + var(--safe-left));
        padding-right: 10px;
    }

    .app-shell.sidebar-collapsed .sidebar-brand span,
    .app-shell.sidebar-collapsed .new-chat-button span,
    .app-shell.sidebar-collapsed .sidebar-section-label,
    .app-shell.sidebar-collapsed .conversation-list,
    .app-shell.sidebar-collapsed .history-empty,
    .app-shell.sidebar-collapsed .profile-copy,
    .app-shell.sidebar-collapsed .profile-chevron {
        display: none;
    }

    .app-shell.sidebar-collapsed .sidebar-top {
        padding: 0;
        flex-direction: column;
        gap: 8px;
    }

    .app-shell.sidebar-collapsed .new-chat-button {
        justify-content: center;
        padding: 0;
    }

    .app-shell.sidebar-collapsed .profile-trigger {
        grid-template-columns: 1fr;
        justify-items: center;
        padding: 8px 0;
    }

    .app-shell.sidebar-collapsed .profile-menu {
        width: 276px;
        left: 56px;
        bottom: 0;
    }
}

/* MOBILE — condition « mode telephone »

   `max-width: 820px` seul classait un iPhone couche comme bureau : en paysage
   il mesure 852px de LARGE. Tout ce bloc — tiroir, backdrop, cibles C4, champs
   16px de C5 et C7 — devenait inerte des que l'appareil etait tourne, et le
   rail compact reserve a `min-width: 821px` prenait sa place. Mesure sur
   appareil reel : backdrop et geste de fermeture morts en paysage.

   La largeur ne decrit pas l'appareil, elle decrit une orientation. Le critere
   juste est la conjonction d'une CAPACITE et d'une GEOMETRIE de telephone :

     (pointer: coarse)   pointeur grossier, donc pas une souris ;
     (max-height: 520px) petit cote a l'horizontale, donc un telephone couche.

   Un telephone a toujours un petit cote : en portrait la largeur passe sous
   820px, en paysage la hauteur passe sous 520px. Une tablette n'a ni l'un ni
   l'autre — 744px de petit cote sur iPad mini, 820px sur iPad Air — et garde
   donc sa mise en page bureau, inchangee. Un bureau a pointeur fin est exclu
   par `pointer: coarse` meme dans une fenetre volontairement basse.

   Le seuil de 820px est conserve tel quel : il couvre deja le portrait
   telephone et les petites tablettes, et le deplacer aurait bascule de vrais
   petits bureaux en interface tactile. La virgule ajoute un cas, elle n'en
   retire aucun.

   Meme condition cote JavaScript, dans `PHONE_MODE_QUERY`. */

@media (max-width: 820px), (pointer: coarse) and (max-height: 520px) {
    .app-shell {
        grid-template-columns: 1fr;
    }

    /* Le tiroir est `position: fixed`, donc hors de la grille `.app-shell` :
       la correction C3 ne l'a jamais couvert. Sans `height`, `bottom: 0` se
       resout sur le viewport LARGE de Safari iOS — exactement le defaut que le
       commentaire de `.app-shell` decrit. Le bas du tiroir, donc le bloc profil
       et le padding de safe-area, passe sous la barre d'outils.

       Ici la barre est TOUJOURS deployee : `body { overflow: hidden }` et le
       defilement se fait dans `.chat-window`, jamais au niveau du document, or
       Safari ne retracte sa barre que sur un defilement de document. Le
       recouvrement est donc permanent, pas transitoire.

       `100svh` borne le tiroir au plus petit viewport, comme C3 l'a valide sur
       appareil reel. `inset: 0 auto 0 0` est conserve : sur un moteur sans
       `svh` la declaration est ignoree et `bottom: 0` reprend le comportement
       actuel. Avec `svh`, la boite est sur-contrainte et `bottom` est ignore au
       profit de la hauteur. */
    /* `touch-action` reevalue apres C8. L'audit initial l'avait ecarte parce
       que le telephone couche recevait la mise en page bureau : les gestes
       etaient inertes, la propriete n'avait rien a arbitrer. Depuis le mode
       telephone en paysage, Pointer Events et defilement natif coexistent
       reellement sur ce meme tiroir, et l'arbitrage devient necessaire.

       Avec la valeur par defaut `auto`, WebKit arme ses reconnaisseurs de pan
       sur les DEUX axes. Un glissement horizontal FRANC franchit le seuil de
       pan en une ou deux trames, Safari s'approprie le contact et emet
       `pointercancel` : le geste est perdu avant d'avoir pu etre mesure. Un
       glissement LENT reste sous ce budget et laisse le contact au DOM — d'ou
       le comportement asymetrique mesure sur iPhone 15.

       `pan-y` ne rend au navigateur que l'axe vertical. Le defilement de la
       sidebar reste donc entierement natif (D2 intact, aucun `preventDefault`
       n'est appele nulle part), tandis que l'axe horizontal n'est plus
       revendique : les `pointermove` vers la gauche continuent d'arriver.
       Un pan vertical emet toujours `pointercancel`, ce qui abandonne
       correctement le geste au profit du defilement.

       `none` reste proscrit : il emporterait le defilement vertical.

       Accessibilite : `pan-y` seul desactiverait le zoom par pincement SUR CE
       TIROIR (le `<meta viewport>` ne pose ni `user-scalable=no` ni
       `maximum-scale`, le pincement est donc bien disponible aujourd'hui). La
       seconde declaration le restitue. Un moteur qui refuse la syntaxe a deux
       valeurs ignore cette ligne et conserve `pan-y` : la correction du geste
       n'est jamais suspendue au support de `pinch-zoom`. */
    .sidebar {
        width: min(326px, 88vw);
        position: fixed;
        inset: 0 auto 0 0;
        height: 100svh;
        transform: translateX(-102%);
        box-shadow: 28px 0 70px rgba(0,0,0,.55);
        touch-action: pan-y;
        touch-action: pan-y pinch-zoom;
    }

    .app-shell.mobile-sidebar-open .sidebar {
        transform: translateX(0);
    }

    .mobile-sidebar-backdrop {
        position: fixed;
        z-index: 15;
        inset: 0;
        background: rgba(0, 3, 8, .64);
        backdrop-filter: blur(4px);
    }

    .app-shell.mobile-sidebar-open .mobile-sidebar-backdrop {
        display: block;
    }

    /* Cibles tactiles : 44 x 44 minimum au doigt. Les pictogrammes gardent
       leur taille, seule la boite interactive grandit. */

    .auth-tab {
        min-height: 44px;
    }

    .ghost-icon-button {
        width: 44px;
        height: 44px;
    }

    /* La colonne du bouton « ••• » suit sa nouvelle largeur (44 + 3 de marge),
       sinon la piste de 34px l'ecraserait. */
    .conversation-row {
        grid-template-columns: minmax(0, 1fr) 47px;
    }

    .conversation-open {
        min-height: 44px;
    }

    .conversation-more {
        width: 44px;
        height: 44px;
    }

    /* Le menu reste aligne juste sous le bouton, qui occupe desormais toute la
       hauteur de la ligne. */
    .conversation-menu {
        top: 44px;
    }

    .conversation-menu button {
        min-height: 44px;
    }

    .profile-menu > button {
        min-height: 44px;
    }

    .mobile-menu-button {
        width: 44px;
        height: 44px;
        display: grid;
    }

    .chat-window {
        padding: 30px 16px 175px;
    }

    .composer-zone {
        padding: 0 calc(10px + var(--safe-right)) calc(12px + var(--safe-bottom)) calc(10px + var(--safe-left));
    }

    .composer {
        min-height: 60px;
        border-radius: 23px;
    }

    /* Cadrage global apres connexion. Les deux champs d'authentification sont
       imbriques dans `#auth-form label` (.88rem) et recoivent sa taille via
       `button, input, textarea { font: inherit }` : 14.08px calcules, sous le
       seuil de 16px. Safari iOS zoome donc le viewport visuel au focus.

       Le zoom ne repart pas : `showApp()` masque `#auth-screen` alors que le
       champ a encore le focus — cas courant, la soumission se fait au bouton
       « Aller » du clavier. L'element d'ancrage disparait, Safari n'a plus de
       cible depuis laquelle restituer l'echelle, et l'application s'affiche
       trop large et decadree horizontalement. C'est la cause exacte du defaut
       « il faut pincer pour dezoomer apres connexion ».

       Ce n'est pas un debordement : la geometrie ne depasse jamais le viewport
       de mise en page, et `body { overflow: hidden }` interdit deja tout
       defilement horizontal du document. Le symptome est une echelle, d'ou le
       geste de pincement et non de glissement lateral.

       C5 avait traite `#user-input` et `#history-search-input` mais pas ces
       deux champs. Meme regle, meme unite absolue en `px`.

       Hauteur : +2px environ par champ. `.auth-screen` est desormais bornee au
       viewport et defilante, donc ces quelques pixels ne peuvent ni rogner ni
       deplacer quoi que ce soit. Regle confinee au mobile, le formulaire
       bureau est inchange. */
    #auth-form input {
        font-size: 16px;
    }

    /* Safari iOS zoome automatiquement sur un champ dont la font-size calculee
       est inferieure a 16px. `.99rem` valait 15.84px, juste sous le seuil.
       L'unite est volontairement `px` et non `rem` : le seuil iOS est un
       absolu, une future taille de racine ne doit pas le reintroduire.
       La hauteur ne bouge pas : `min-height: 45px` reste superieure a
       11 + (16 x 1.48) + 7 = 41.68px, donc ni clipping ni deplacement du
       composeur, et C3 reste intact. */
    #user-input {
        font-size: 16px;
    }

    /* 44 au lieu de 40. La hauteur du composeur ne bouge pas : elle est fixee
       par `#user-input` (min-height 45px), qui reste le plus grand element de
       la rangee. C3 n'est donc pas touche. */
    .composer-icon-button,
    .send-button {
        width: 44px;
        height: 44px;
    }

    .mic-button {
        display: none;
    }

    .message-bubble {
        max-width: 88%;
    }

    .typing-indicator {
        padding: 0 16px;
    }
}

/* Tiroir sur viewport court — telephone en paysage.

   Le mobilier non defilant du tiroir coute environ 338px : 18 de padding haut,
   45 de `.sidebar-top`, 95 pour « Nouveau chat » et ses marges, 24 de libelle
   « Recents », 54 de recherche, 69 de bloc profil, 33 de padding bas avec la
   safe-area. C4 a legitimement fait grandir plusieurs de ces cibles a 44px.

   En paysage sur iPhone 15, le viewport fait environ 342px de haut. Le mobilier
   consomme donc la quasi-totalite de la hauteur et `.conversation-list`, seul
   element defilant, se retrouve reduit a quelques pixels : c'est la cause du
   defaut de defilement observe en paysage des C1.

   Correction : sur un viewport court, le defilement passe de la liste au tiroir
   entier. Recherche, conversations et profil deviennent tous atteignables par
   un seul defilement vertical. Le profil n'est plus epingle en bas dans ce cas
   precis, compromis assume et limite aux viewports courts.

   Seuil `520px` : au-dessus de tous les paysages telephone (<= 430px) et bien
   en dessous de tous les portraits telephone (>= 553px sur iPhone SE). Le
   portrait ne voit donc aucun changement.

   CORRECTIF — la condition `max-width: 820px` posee en C8 rendait ce bloc
   inoperant precisement la ou il devait agir. Un iPhone 15 en paysage mesure
   852px de LARGE : il ne franchit aucun point de rupture mobile. Mesure sur
   appareil reel : aucun defilement du tout en paysage, et le rail compact
   reserve a `min-width: 821px` s'affichait — deux confirmations independantes
   que le telephone couche recoit la mise en page bureau.

   La hauteur est le seul critere geometrique pertinent ici : un viewport court
   est court, quelle que soit la mise en page servie.

   CORRECTIF BUREAU — `pointer: coarse` avait ete conserve pour garder la regle
   hors du bureau. C'est exactement cette restriction qui laissait une fenetre
   PC basse sans strategie : le mobilier non defilant y coute les memes ~312px,
   et une fois la geometrie de la piste corrigee sur `.app-shell`, le reliquat
   laisse a `.conversation-list` redevient certes defilant, mais trop court pour
   etre utilisable bien avant d'etre nul.

   La condition passe donc a la hauteur seule. C'est un ELARGISSEMENT STRICT :
   tout appareil tactile qui declenchait ce bloc le declenche encore, le
   comportement paysage valide sur appareil reel est inchange. Seules entrent en
   plus les fenetres a pointeur fin et viewport court, et elles n'heritent que
   de cette strategie de defilement — aucune cible tactile, aucun tiroir, aucun
   backdrop, aucun mode telephone : ces blocs-la restent conditionnes par
   `max-width: 820px` ou `pointer: coarse` et ne sont pas touches.

   Le seuil `520px` n'est pas rejoue : c'est la constante deja etablie et
   validee ici, pas une hauteur deduite d'un ecran de developpement. */
@media (max-height: 520px) {
    .sidebar {
        overflow-y: auto;
    }

    .conversation-list {
        flex: 0 0 auto;
        overflow-y: visible;
    }
}

@media (max-width: 480px) {
    /* `min-height: auto` a ete retire : la regle de base ne declare plus de
       `min-height`, cette surcharge n'avait donc plus de cible. */
    .auth-screen {
        padding: 27px 22px;
    }

    .welcome-state h1 {
        font-size: 2rem;
    }

    .hero-mark {
        width: 68px;
        height: 68px;
        margin-bottom: 24px;
    }

    .message-avatar {
        display: none;
    }

    .message-row {
        gap: 0;
    }

    .message-bubble {
        max-width: 94%;
    }

    .disclaimer {
        display: none;
    }
}


/* ───────────────────────────────
   Streaming, Markdown et code
─────────────────────────────── */
.send-button.stop-mode{background:#f1f4f8;color:#07101d;box-shadow:0 8px 20px rgba(255,255,255,.12)}
.markdown-body{min-width:0}.markdown-body p{margin:0 0 .85em}.markdown-body p:last-child{margin-bottom:0}
.markdown-body h1,.markdown-body h2,.markdown-body h3{margin:1.15em 0 .55em;color:#f7f9fd;line-height:1.3}
.markdown-body h1:first-child,.markdown-body h2:first-child,.markdown-body h3:first-child{margin-top:0}
.markdown-body h1{font-size:1.45rem}.markdown-body h2{font-size:1.25rem}.markdown-body h3{font-size:1.08rem}
.markdown-body ul,.markdown-body ol{margin:.45em 0 1em 1.35em;padding:0}.markdown-body li{margin:.32em 0}
.markdown-body blockquote{margin:.8em 0;padding:.3em 0 .3em 1em;border-left:3px solid rgba(69,135,255,.65);color:#aebbd0}
.markdown-body a{color:#67a6ff;text-decoration:none}.markdown-body a:hover{text-decoration:underline}
.inline-code{padding:.16em .38em;border:1px solid rgba(128,158,199,.16);border-radius:6px;background:rgba(255,255,255,.055);color:#d9e7ff;font-family:"Cascadia Code","SFMono-Regular",Consolas,monospace;font-size:.9em}
.markdown-spacer{height:.36em}.code-block{margin:1em 0;overflow:hidden;border:1px solid rgba(113,149,202,.20);border-radius:13px;background:#020711}
.code-block-head{min-height:39px;padding:0 10px 0 14px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid rgba(113,149,202,.16);background:#0b1320;color:#8999ae;font-size:.75rem}
.copy-code-button{padding:6px 9px;border:0;border-radius:7px;background:transparent;color:#aebdd1;cursor:pointer}.copy-code-button:hover{background:rgba(255,255,255,.06);color:white}
.code-block pre{margin:0;padding:17px;overflow-x:auto}.code-block code{color:#d8e5f8;font-family:"Cascadia Code","SFMono-Regular",Consolas,monospace;font-size:.86rem;line-height:1.62;white-space:pre}

/* v0.11 — recherche historique et actions de message */
.history-search {
    min-height: 38px;
    margin: 0 4px 10px;
    padding: 0 10px;
    display: flex;
    align-items: center;
    gap: 8px;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: rgba(255,255,255,.025);
}
.history-search:focus-within {
    border-color: rgba(47,127,255,.48);
    background: rgba(47,127,255,.045);
}
.history-search svg {
    width: 16px;
    height: 16px;
    flex: 0 0 auto;
    color: #77869a;
}
.history-search input {
    min-width: 0;
    width: 100%;
    padding: 8px 0;
    border: 0;
    background: transparent;
    color: var(--text);
    font-size: .82rem;
}
.history-search input::placeholder { color: #5f6d80; }
.message-content-box {
    min-width: 0;
    max-width: min(760px, 82%);
    display: flex;
    flex-direction: column;
}
.message-content-box .message-bubble { max-width: 100%; }
.message-row.user .message-content-box { align-items: flex-end; }
.message-actions {
    min-height: 30px;
    margin-top: 4px;
    display: flex;
    align-items: center;
    gap: 2px;
    opacity: 0;
    transform: translateY(-2px);
    transition: opacity .14s ease, transform .14s ease;
}
.message-row:hover .message-actions,
.message-actions:focus-within {
    opacity: 1;
    transform: translateY(0);
}
.message-row.user .message-actions { justify-content: flex-end; }
.message-action-button {
    width: 30px;
    height: 30px;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: #78889d;
    cursor: pointer;
}
.message-action-button:hover {
    background: rgba(255,255,255,.055);
    color: #dbe7f7;
}
.message-action-button svg { width: 16px; height: 16px; }
/* Meme condition « mode telephone » que le bloc principal : ces cibles C4 et
   ce champ 16px de C5 disparaissaient eux aussi en paysage. */
@media (max-width: 820px), (pointer: coarse) and (max-height: 520px) {
    .message-content-box { max-width: 88%; }
    .message-actions { opacity: .78; }
    /* Cibles tactiles 44 x 44. Les SVG restent a 16px. */
    .message-action-button { width: 44px; height: 44px; }
    .history-search { min-height: 44px; }
    .copy-code-button { min-height: 44px; }
    /* Anti-zoom iOS : `.82rem` valait 13.12px. Le champ passe a 35px de haut,
       toujours sous les 44px du conteneur, qui garde donc sa cible C4. */
    #history-search-input { font-size: 16px; }
}

/* Actions de message sans survol. La revelation historique dependait de
   `.message-row:hover`, indisponible sur un pointeur grossier : Copier,
   Regenerer et Modifier restaient donc invisibles au doigt.

   La regle `max-width: 820px` ci-dessus ne couvre que les petits ecrans. Un
   appareil tactile plus large — tablette en paysage — restait a `opacity: 0`.
   La condition qui decrit reellement le probleme est l'absence de survol, pas
   la largeur : d'ou `hover: none`.

   `transform: none` est necessaire et pas cosmetique : l'etat masque combine
   `opacity: 0` et `translateY(-2px)`, et la revelation au survol remet les
   deux. Ne retablir que l'opacite laissait la barre decalee de 2px en
   permanence, soit un etat revele incomplet.

   Opacite `.78` et non `1` : la barre reste discrete au lieu de devenir une
   barre d'outils permanente contrastee. Icones, tailles et styles sont
   inchanges, et les cibles 44 x 44 de C4 ne sont pas touchees.

   Bloc purement additif : sur un pointeur fin, `hover: none` ne s'applique
   pas et le comportement de survol historique du bureau est intact. */
@media (hover: none) {
    .message-actions {
        opacity: .78;
        transform: none;
    }
}

/* Densite du chat en paysage telephone.

   Meme condition physique que le bloc du tiroir plus haut — appareil tactile,
   viewport court — mais ce bloc est place en FIN de fichier a dessein :
   plusieurs des regles de base qu'il surcharge (`.markdown-body`,
   `.code-block`, `.message-actions`) sont declarees apres lui. Une media query
   n'ajoute aucune specificite ; place plus haut, ces surcharges perdraient
   silencieusement.

   Le probleme n'est pas la taille de police en soi, c'est le budget vertical.
   En paysage le viewport fait environ 342px de haut, et `.chat-window` y
   appliquait le padding concu pour le portrait : 30px en haut, 175px en bas.
   Le composeur reel n'en occupant qu'environ 119, une trentaine de pixels
   etaient perdus, et il ne restait qu'environ 161px de lecture — d'ou une
   reponse qui remplit l'ecran.

   Trois axes :

   1. budget vertical — padding proportionne au composeur reellement affiche,
      avertissement masque comme il l'est deja sous 480px de large ;
   2. typographie — un interligne de 1.72 est genereux sur un viewport haut et
      couteux sur 342px. 1.5 avec un corps legerement reduit fait passer la
      ligne de 27 a 22.6px, soit 16% de hauteur en moins par ligne ;
   3. rythme vertical — marges de messages, de paragraphes et de blocs de code
      resserrees.

   Les marges de `.typing-indicator` sont recalculees pour conserver exactement
   la meme somme qu'avant, -56px : la hauteur que le flex accorde a
   `.chat-window` ne bouge donc pas, et l'indicateur remonte au-dessus du
   composeur raccourci. Les deux invariants — indicateur au-dessus du composeur,
   dernier message au-dessus du composeur — se verifient algebriquement pour
   n'importe quelle hauteur de viewport, puisque tout le calcul flex est
   relatif a celle du panneau.

   Aucune cible tactile n'est touchee : les boutons restent a 44 x 44 et
   `#user-input` a 16px. La taille d'un bouton et celle de son texte sont deux
   choses distinctes, seule la seconde bouge ici. */
@media (pointer: coarse) and (max-height: 520px) {
    /* Grossissement automatique du texte par WebKit.

       Le projet ne declare `text-size-adjust` NULLE PART et n'a aucun reset
       CSS : la propriete reste donc a sa valeur par defaut sur iOS, `auto`,
       qui autorise le « text autosizing » de WebKit. Ce mecanisme majore la
       taille des blocs de texte quand la largeur de mise en page augmente, et
       se declenche typiquement au passage en paysage — c'est exactement le
       defaut que normalize.css neutralise depuis dix ans avec le commentaire
       « Prevent adjustments of font size after orientation changes in iOS ».

       C'est l'hypothese qui explique l'ecart entre 15px declares et un rendu
       percu comme enorme, la ou une reduction de 4% est passee inapercue : le
       facteur s'applique PAR-DESSUS la taille declaree, donc reduire la
       declaration sans neutraliser le facteur ne fait que reduire l'entree
       d'un multiplicateur toujours actif.

       `100%` et non `none` : `none` desactive aussi la mise a l'echelle du
       texte lors d'un zoom utilisateur sur certains moteurs, ce qui est un
       vrai probleme d'accessibilite. `100%` demande seulement « rends le texte
       a la taille specifiee, sans majoration automatique ». Le pinch-to-zoom,
       le reglage aA de Safari et le zoom de page restent entierement
       disponibles — aucune capacite utilisateur n'est retiree.

       Regle volontairement confinee au paysage telephone : le portrait ne
       presente pas le symptome et ne doit pas bouger. Si une majoration y
       etait constatee un jour, la regle remonterait simplement sur `html`. */
    html {
        -webkit-text-size-adjust: 100%;
        text-size-adjust: 100%;
    }

    /* Reserve verticale pour le bouton ☰.

       `.mobile-menu-button` est `position: absolute` dans `.main-panel` : il
       est hors flux et ne reserve donc AUCUN espace. Sa bande occupe
       `16px + safe-top` a `60px + safe-top`, et son `z-index: 10` le fait
       peindre par-dessus la conversation.

       En paysage `safe-top` vaut 0 : la bande commence a 16px alors que le
       padding haut, que j'avais ramene a 12px au commit precedent, faisait
       demarrer le premier message a 12px — donc AU-DESSUS du bouton. Le
       chevauchement etait systematique.

       En portrait le defaut existe structurellement mais reste invisible :
       l'encoche donne un `safe-top` d'environ 59px qui repousse la bande a
       75-119px, hors d'atteinte d'un premier message demarrant a 30px. Le
       portrait est protege par la geometrie de l'appareil, pas par la CSS.
       Sidebar ouverte, le backdrop (`z-index: 15`) recouvre le bouton, d'ou
       l'impression que cet etat etait correct.

       La reserve est verticale et derivee de la geometrie du bouton lui-meme :
       16 de decalage + 44 de hauteur (cible C4, non reduite) + 8 de respiration.
       Aucune largeur n'est sacrifiee — un padding gauche aurait ampute les 852px
       de la conversation entiere pour un bouton qui n'occupe que le premier
       ecran. La reserve defile avec le contenu : elle ne coute rien des que
       l'utilisateur descend. */
    .chat-window {
        padding: calc(68px + var(--safe-top)) 16px 124px;
    }

    .typing-indicator {
        margin: -150px auto 94px;
    }

    .disclaimer {
        display: none;
    }

    .message-row {
        margin-bottom: 14px;
    }

    /* Corps de message a 14px. Unite `px` volontaire : `rem` dependrait de la
       taille racine, or l'objectif est ici une taille de rendu maitrisee, pas
       une proportion.

       13px, mesure sur appareil, s'est revele legerement trop petit pour une
       lecture prolongee. 14px reste 11% sous les 15.68px d'origine et surtout
       conserve tout l'acquis : `text-size-adjust: 100%` neutralise toujours le
       grossissement automatique de WebKit, qui etait le vrai facteur. La ligne
       passe de 27px a 19.6px, soit 27% de hauteur en moins.

       14px ne concerne aucun champ editable : C5 vise `#user-input` et
       `#history-search-input` pour empecher le zoom iOS au focus, pas le texte
       des messages. Les cibles tactiles restent a 44 x 44, la taille d'un
       bouton et celle de son texte etant deux choses distinctes. */
    .message-bubble {
        font-size: 14px;
        line-height: 1.4;
    }

    .markdown-body p {
        margin: 0 0 .6em;
    }

    /* Les titres suivaient le corps d'origine : 23.2 / 20 / 17.3px, hors
       d'echelle dans 342px de haut. La hierarchie etablie au commit precedent
       est conservee a l'identique — corps +4 / +2 / +1 — et simplement
       decalee d'un pixel avec lui. Sans ce decalage, `h3` retomberait a la
       taille exacte du corps et la hierarchie disparaitrait. */
    .markdown-body h1 {
        font-size: 18px;
    }

    .markdown-body h2 {
        font-size: 16px;
    }

    .markdown-body h3 {
        font-size: 15px;
    }

    .markdown-body h1,
    .markdown-body h2,
    .markdown-body h3 {
        margin: .75em 0 .4em;
    }

    .markdown-body ul,
    .markdown-body ol {
        margin: .3em 0 .7em 1.35em;
    }

    .code-block {
        margin: .7em 0;
    }

    .code-block pre {
        padding: 11px 13px;
    }

    /* Code maintenu a 12px malgre le corps qui remonte a 14. Une fonte a
       chasse fixe parait plus grosse qu'une proportionnelle de meme taille —
       glyphes plus larges, hauteur d'x pleine — donc 12 contre 14 est un
       appariement equilibre, pas un ecart de deux pixels subi. */
    .code-block code {
        font-size: 12px;
        line-height: 1.4;
    }

    /* Ecran d'accueil. `clamp(2rem, 4vw, 3rem)` est indexe sur la LARGEUR : en
       paysage 4vw vaut environ 34px, un titre qui occupe a lui seul un dixieme
       de la hauteur. Meme classe de defaut que le reste de ce bloc, une taille
       calibree pour un viewport haut appliquee a un viewport court. */
    .welcome-state h1 {
        font-size: 1.5rem;
    }

    .welcome-state p {
        font-size: 14px;
    }

    .hero-mark {
        width: 52px;
        height: 52px;
        margin-bottom: 16px;
        font-size: 1.3rem;
    }

    .welcome-line {
        margin: 16px 0 12px;
    }

    /* Le composeur maigrit par son padding, pas par ses commandes : les 44 x 44
       de C4 et les 16px de C5 sont intacts, `#user-input` garde ses 45px de
       hauteur minimale et donc C3 sa geometrie. */
    .composer {
        min-height: 0;
        padding: 6px 10px 6px 13px;
    }

    .composer-zone {
        padding-bottom: calc(8px + var(--safe-bottom));
    }
}
