/* =========================================================================
   The floating chat.

   Asked for on 2026-09-05, and called the most important thing on the list:
   "The website should have a floating chat button. Any visitor has any
   question, it should ask in that chat and you have to reply to that
   customer."

   Its own stylesheet rather than an addition to styles.css: this is one small
   thing pinned to the corner of a very large page, it is the piece most likely
   to be restyled on its own, and keeping it here means a change to it can
   never disturb a section of the site it does not touch.

   RTL IS NOT AN AFTERTHOUGHT HERE. Every edge below is logical —
   inset-inline-end, margin-inline-start, border-start-start-radius — so on
   /ar/ the button sits bottom-LEFT, the panel opens from the left, and the
   bubbles swap sides, without one [dir="rtl"] override. The page already sets
   dir on <html>; this simply obeys it.

   Colours are the site's own variables where the widget sits on the page, and
   literals only inside the dark header, which has no variable of its own.
   ========================================================================= */

.chat {
  /* Every custom property the widget reads, fixed to the value that was
     already its fallback below, so the widget cannot inherit a page theme —
     light or dark — through the tokens it shares a name with. Without this a
     dark :root elsewhere on the page reaches straight through var(--ink,
     #111827) and the rest, and the widget goes near-white text on its own
     white panel. The widget is one small thing pinned to a corner; it should
     never change colour because a page section three scrolls away did. */
  --body: #4A5561;
  --border: #E3E9F0;
  --border-strong: #C9D3DF;
  --faint: #6B7683;
  --ink: #111827;
  --night: #0B1220;
  --night-faint: #8FA6C2;
  --page: #FBFCFE;
  --primary: #2563EB;
  --primary-dk: #1D4ED8;
  --radius-lg: 8px;
  --radius-pill: 100px;
  --radius-xl: 14px;
  --shadow-primary: 0 10px 24px rgba(37, 99, 235, .28);
  --shadow-xl: 0 44px 100px rgba(17, 24, 39, .16);
  --surface: #fff;
  --warn: #A16207;
  color: var(--ink);

  position: fixed;
  /* --chat-keyboard is how much of the bottom is covered by Safari's toolbar
     or the software keyboard; chat.js writes it, and it is 0 on a desktop.
     Here rather than in the phone block because a keyboard is not only a
     phone's: a tablet with one attached is wider than that breakpoint. */
  inset-block-end: calc(20px + var(--chat-keyboard, 0px));
  inset-inline-end: 20px;
  /* Above everything the page floats: its sections are in the single digits,
     the language menu is at 50, the sticky header at 100 and the scroll
     hairline at 120. It was 90, so the header drew over the dimmed page on a
     phone — a bright pill on a dark screen — and swallowed a tap meant for the
     scrim. Below .skip at 999, which must stay reachable from the keyboard. */
  z-index: 130;
  font-family: inherit;
}

/* ------------------------------------------------------------- the button */

.chat-open {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 13px 20px;
  border: 0;
  border-radius: var(--radius-pill, 100px);
  background: var(--primary, #2563EB);
  color: #fff;
  font: inherit;
  font-size: 15px;
  /* 600, because every button on this site is 600. It was 500 — the pill was
     the right shape in the wrong weight. */
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--shadow-primary, 0 10px 24px rgba(37, 99, 235, .28));
  transition: background 160ms ease, transform 160ms ease;
}

/* Before the page has been scrolled past the hero there is no button at all —
   chat.js sets and clears this; see "when it first appears" there for why.
   Spelled out because the display above beats the browser's own rule for
   `hidden`, which is the same reason .chat-panel[hidden] exists below. */
.chat-open[hidden] { display: none; }

.chat-open:hover { background: var(--primary-dk, #1D4ED8); }
.chat-open:active { transform: translateY(1px); }

.chat-open svg { width: 20px; height: 20px; flex: none; }

/* Something arrived while the panel was shut. */
.chat-open .chat-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #FDE047;
  box-shadow: 0 0 0 3px rgba(253, 224, 71, .35);
}

/* --------------------------------------------------------------- the panel */

.chat-panel {
  display: flex;
  flex-direction: column;
  width: 360px;
  max-width: calc(100vw - 40px);
  height: 480px;
  /* Never squeezed below its own header and composer. On a very short screen —
     a phone held sideways with the keyboard up — it is better that the top of
     the conversation runs off than that the Send button is clipped away, and
     the panel is held to the bottom, so what goes is the oldest of it. */
  min-height: 220px;
  /* dvh, not vh: on iOS vh is measured with Safari's toolbars hidden, so a
     height in vh is taller than the screen it is standing on. --chat-visible
     is nearer still — the height left once the keyboard is up.

     98px is what stands below the panel and has to be left alone: the 20px it
     is held off the bottom, the 46px button, the 12px between them, and 20px
     so the header is not flush against the top of the screen. Without it a
     short window — a phone held sideways — puts the header off the top, which
     is the same fault that was photographed in portrait.

     vh first and dvh second, always: a browser that cannot parse dvh drops
     the whole declaration and the panel loses its cap entirely, so the version
     every browser understands is declared first and the truer one overrides it
     where it is understood. */
  max-height: calc(var(--chat-visible, 100vh) - 98px);
  max-height: calc(var(--chat-visible, 100dvh) - 98px);
  margin-block-end: 12px;
  overflow: hidden;
  background: var(--surface, #fff);
  border: 1px solid var(--border, #E3E9F0);
  border-radius: var(--radius-xl, 14px);
  box-shadow: var(--shadow-xl, 0 44px 100px rgba(17, 24, 39, .16));
}

.chat-panel[hidden] { display: none; }

/*
   The page behind the open sheet, dimmed.

   Nothing on a desktop: there the widget is a card on the corner of a page and
   that is right. The block at the foot of this file turns it on — at the phone
   width, and on any screen too short to stand a card on — where the panel
   becomes a sheet over the page and has to read as one. `hidden` wins over
   that, so a shut widget never swallows a tap.
*/
.chat-scrim { display: none; }
.chat-scrim[hidden] { display: none; }

.chat-head {
  display: flex;
  flex: none;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  background: var(--night, #0B1220);
  color: #fff;
}

.chat-head b { font-size: 15px; font-weight: 600; }

/*
   44px, which is what every other control here already is and what the app
   uses everywhere. It was 28 — the one outlier, and the hardest thing on the
   widget to hit with a thumb.

   The negative block margin keeps the header exactly the height it was: the
   box is 44px to a thumb and 28px — its old size — to the layout around it.
*/
.chat-close {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-inline-start: auto;
  margin-block: -8px;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: var(--radius-lg, 8px);
  background: transparent;
  color: var(--night-faint, #8FA6C2);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}

.chat-close:hover { background: rgba(255, 255, 255, .08); color: #fff; }

/* ------------------------------------------------------------ the talking */

.chat-log {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  /* A swipe that reaches the oldest message stops there rather than carrying
     on into the page behind the panel. The wheel is held the same way, by the
     data-lenis-prevent chat.js writes on this element. */
  overscroll-behavior: contain;
  margin: 0;
  padding: 16px;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 12px;
  background: var(--page, #FBFCFE);
}

.chat-log li { display: flex; flex-direction: column; gap: 4px; max-width: 88%; }

/* Theirs on the start edge, ours on the end edge — which mirrors itself on
   the Arabic page without a second rule. */
.chat-log .them { align-self: flex-start; }
.chat-log .us { align-self: flex-end; }

.chat-log p {
  margin: 0;
  padding: 10px 13px;
  border-radius: var(--radius-xl, 14px);
  font-size: 14px;
  line-height: 1.5;
  /* Whatever a stranger typed, drawn as text and never as markup. The script
     writes it with textContent; this only keeps a long word from bursting the
     bubble. */
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

.chat-log .them p {
  background: var(--surface, #fff);
  border: 1px solid var(--border, #E3E9F0);
  border-start-start-radius: 4px;
  color: var(--ink, #111827);
}

.chat-log .us p {
  background: var(--primary, #2563EB);
  border-end-end-radius: 4px;
  color: #fff;
}

/*
   The line that says a message landed.

   Deliberately not a bubble and deliberately unattributed: it is the widget
   saying the message arrived, not somebody answering. Asked for on
   2026-09-05: "It should have some message in chat so customer know that
   someone heard him and he can wait." It is never stored, so the Command
   Center never fills with rows nobody wrote.
*/
.chat-log .chat-note {
  align-self: center;
  max-width: 100%;
  text-align: center;
}

/* Who wrote it: the desk, and whether a person did. Both, always. */
.chat-log small {
  font-size: 11px;
  color: var(--faint, #6B7683);
  padding-inline: 4px;
}

.chat-log .us small { text-align: end; }

/* ----------------------------------------------------------- the composer */

.chat-form {
  flex: none;
  border-block-start: 1px solid var(--border, #E3E9F0);
  padding: 12px;
  background: var(--surface, #fff);
}

/* `hidden` has to win over any display this file sets, or the address label
   stays on screen after the address has been given — which it did, until it was
   seen in a browser. */
.chat-form [hidden] { display: none; }

.chat-ask {
  display: block;
  font-size: 12px;
  color: var(--body, #4A5561);
  margin-block-end: 6px;
}

.chat-form input,
.chat-form select,
.chat-form textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border-strong, #C9D3DF);
  border-radius: var(--radius-lg, 8px);
  font: inherit;
  font-size: 14px;
  color: var(--ink, #111827);
  background: var(--surface, #fff);
}

.chat-form input:focus-visible,
.chat-form select:focus-visible,
.chat-form textarea:focus-visible {
  outline: 2px solid var(--primary, #2563EB);
  outline-offset: 1px;
}

/* The three boxes stacked, each with room under it for the next. A select is
   sized by the browser's own control on a phone, so it gets the same minimum
   height as everything else here rather than whatever the platform picks. */
.chat-form input,
.chat-form select { margin-block-end: 8px; }
.chat-form select { min-height: 44px; }
.chat-start { width: 100%; }

/*
   One line while it is empty, growing with what is typed — chat.js writes the
   height, this holds the floor and the ceiling.

   112px is four lines on a desktop and three and a half on a phone, and it is
   the ceiling rather than a rounder number because of the shortest screen this
   has to survive: a phone held sideways with the keyboard up, where the panel
   is down to its 220px floor. Header 56 + padding 24 + 112 + the status line 22
   is 214, so the Send button is still inside the panel there. Past the cap the
   box scrolls, which is what every other chat does.
*/
.chat-form textarea { resize: none; min-height: 44px; max-height: 112px; }

.chat-row { display: flex; align-items: flex-end; gap: 8px; }

.chat-send {
  flex: none;
  /* 44px, the same as the box beside it and every other control here. */
  min-height: 44px;
  padding: 11px 18px;
  border: 0;
  /*
     A pill, like every other primary button on this site — "Start the free
     week", "Create my account", "Download for Android", and the small one in
     the top bar are all radius 100px at weight 600. This was an 8px corner at
     weight 500: the widget had borrowed the site's colour and then drawn its
     own button.
  */
  border-radius: var(--radius-pill, 100px);
  background: var(--primary, #2563EB);
  color: #fff;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

.chat-send:disabled { opacity: .55; cursor: default; }

.chat-status {
  display: block;
  min-height: 16px;
  margin-block-start: 6px;
  font-size: 12px;
  color: var(--faint, #6B7683);
}

.chat-status.bad { color: var(--warn, #A16207); }

/*
   A phone, upright or held sideways.

   Reported on 2026-09-05, after two sets of measurements that passed: "it
   does not look responsive design at all."

   Nothing overflowed. The fault was proportion and behaviour. The panel was
   sized by what was in it, so the opening greeting alone drew a 274px card —
   34% of the screen — floating in the middle of the page with the dark hero
   above it, beside it and below it, no dimming behind, and the page's own
   "Start the free week" button sliced in half by its top edge. Then it grew to
   70% of the screen once a conversation had five or six messages in it.

   So on a phone it is not a card at all. It is a sheet on the bottom edge of
   the screen, at ONE height whether the conversation is one line or twenty,
   with the page dimmed behind it — which is what WhatsApp, iMessage and WeChat
   all do, and therefore what a phone chat is expected to look like.

   AND ON A PHONE HELD SIDEWAYS, which the width alone does not catch: 667x320
   and 812x375 are both wider than 480, so they were getting the desktop card —
   222px of panel standing on a 320px screen, its dark header drawn straight
   over the page's own top bar with 53px of overlap, the language pill and
   "Start the free week" sliced by its top edge, and 50px of conversation
   showing. That is the same picture objected to in portrait, so it gets
   the same answer. The second condition is the one that catches it: a screen
   with no height to spare, on something no wider than the largest phone. The
   960px keeps a desktop window that has merely been dragged short as a card,
   which is what it should be.

   A real desktop is untouched: a floating panel on the corner of a page is
   right there, and that is what everything above this block still says.

   --chat-visible and --chat-keyboard are written by chat.js from
   visualViewport. iOS lays fixed elements out against the LARGE viewport, so
   the bottom of this widget sits behind Safari's toolbar, and behind the
   keyboard once the box has focus. Those two numbers are how much is really
   there and how much is really covered. Both have fallbacks, so the widget is
   correct in a browser that has neither.

   env(safe-area-inset-*) is inert until the page's viewport meta says
   viewport-fit=cover — it is written here so this is already right if it ever
   does, and it costs nothing meanwhile. Left and right are read as one value
   because start and end swap on /ar/ and a notch does not.
*/
@media (max-width: 480px), (max-height: 480px) and (max-width: 960px) {
  /* Shut: the launcher alone, held off the corner like any floating button. */
  .chat {
    --chat-edge: max(env(safe-area-inset-left, 0px), env(safe-area-inset-right, 0px));
    inset-block-end: calc(12px + env(safe-area-inset-bottom, 0px) + var(--chat-keyboard, 0px));
    inset-inline-end: calc(12px + var(--chat-edge));
    inset-inline-start: calc(12px + var(--chat-edge));
  }

  /* Open: on the edges of the screen, not held off them. chat.js writes the
     class, rather than :has() reading the panel, so this is right in a browser
     that does not have :has() — the same insurance as the vh line above. */
  .chat.is-open {
    inset-block-end: var(--chat-keyboard, 0px);
    inset-inline-start: 0;
    inset-inline-end: 0;
  }

  /*
     One control, not two.

     The launcher stayed on screen under the open panel, overlapping whatever
     the page happened to have there — two floating buttons doing the same job,
     which reads as a mistake. The sheet has its own close in its header.
  */
  .chat.is-open .chat-open { display: none; }

  .chat-scrim {
    position: fixed;
    inset: 0;
    display: block;
    background: rgba(11, 18, 32, .5);
    /* A drag on the dimmed page does not scroll the page; a tap on it shuts
       the sheet, which is what a sheet does everywhere else on a phone. */
    touch-action: none;
  }

  /* Both of these paint over the scrim. Neither is positioned, and a
     positioned box otherwise draws above every in-flow box beside it. */
  .chat-panel,
  .chat-open { position: relative; z-index: 1; }

  .chat-panel {
    /* Edge to edge: the container above is already both edges wide. */
    width: auto;
    max-width: none;
    /*
       The height that does not move.

       85dvh is generous enough that a greeting on its own still looks like a
       conversation waiting to happen, and short enough that the page stays
       visible above it, so it reads as something over the page. What it is
       NOT is content-driven — a panel that changes size as you talk to it is
       the whole of what the complaint was about.
    */
    height: 85vh;
    height: 85dvh;
    /*
       Except where there is not that much screen: a keyboard up, or a phone
       held sideways. --chat-visible is what is really in front of somebody,
       and 24px leaves the top of the sheet clear of the very top of the
       screen. vh before dvh here too, and for the same reason.
    */
    max-height: calc(var(--chat-visible, 100vh) - 24px - env(safe-area-inset-top, 0px));
    max-height: calc(var(--chat-visible, 100dvh) - 24px - env(safe-area-inset-top, 0px));
    margin-block-end: 0;
    /* Rounded where it meets the page, square and borderless where it meets
       the screen — a sheet, not a card resting on the bottom edge. */
    border-inline: 0;
    border-block-end: 0;
    border-start-start-radius: var(--radius-xl, 14px);
    border-start-end-radius: var(--radius-xl, 14px);
    border-end-start-radius: 0;
    border-end-end-radius: 0;
    /* The home bar, on a phone that has one. Inside the sheet, so the Send
       button is never under it. */
    padding-block-end: env(safe-area-inset-bottom, 0px);
  }

  /*
     16px is not a style choice.

     Under 16px, iOS Safari zooms the whole page in when the field takes focus.
     The widget is then laid out for 375px and drawn on 328px of screen, so its
     right-hand 40px — half the Send button, the end of the launcher — fall off
     the side, and the zoom scrolls the header off the top. That is the picture
     that was sent, and this line is what stops it.
  */
  .chat-form input,
  .chat-form select,
  .chat-form textarea { font-size: 16px; }

  .chat-open { margin-inline-start: auto; }
}

/*
   Held sideways: the same sheet, stopped short of the page's own top bar.

   In portrait the bar stands clear above the sheet on its own, because 85% of
   800px still leaves 120px. In landscape there are only 320px to divide, so the
   sheet reached 48px from the top and cut the language pill and "Start the free
   week" in half — dimmed by the scrim, but a sliced button all the same, and
   that exact picture is what started this.

   84px is the bar at its tallest — 74px before it shrinks on scroll — and ten
   to spare. It replaces the 24px above and only ever bites on a short screen:
   in portrait 85dvh is the smaller of the two and still wins. What it costs is
   36px of conversation on a 320px screen, which is the right way round.
*/
@media (max-height: 480px) and (max-width: 960px) {
  .chat-panel {
    max-height: calc(var(--chat-visible, 100vh) - 84px - env(safe-area-inset-top, 0px));
    max-height: calc(var(--chat-visible, 100dvh) - 84px - env(safe-area-inset-top, 0px));
  }
}

/* Somebody who has asked not to be moved about. */
@media (prefers-reduced-motion: reduce) {
  .chat-open { transition: none; }
}
