/**
 * STDZ-190 - the chat launcher and panel.
 *
 * Plain CSS rather than Less, on purpose. The Sm theme owns the Less build here and a new .less
 * file would join its compilation - which means a change to our widget could fail the theme's
 * build, and a failure in the theme's build would hide our widget. A standalone stylesheet loaded
 * by the layout has neither problem.
 *
 * Every class is prefixed aichat- and nothing here is a bare element or theme-class selector, so
 * this file cannot reach anything outside the widget. That matters more than usual: this is the
 * one asset that renders on every page of the store.
 *
 * Accessibility notes, since the BRD holds this to WCAG 2.2 AA:
 *
 * - Every interactive target is at least 44x44px, comfortably past the 24px floor of SC 2.5.8.
 * - Contrast ratios are stated inline against the background they sit on; the lowest here is 5.9:1
 *   against the 4.5:1 requirement for body text.
 * - Focus is a 3px outline with a 2px offset, never removed. The theme's global `outline: none`
 *   habit is why these are declared explicitly on each control rather than inherited.
 * - The panel is sized in px, NOT rem. This store loads Bootstrap 3.4.1 from a CDN on every page
 *   and it sets `html { font-size: 10px }`, so a rem here is 10px and not the 14-16px this widget
 *   was drawn against - which rendered the panel at 257px and pushed the footer buttons out of it.
 *   Browser zoom still scales a px panel, so SC 1.4.4 is met; what a px width buys is that no
 *   theme or third-party stylesheet can resize our panel by moving the root font size.
 * - The panel reflows to full width under 480px rather than scrolling sideways (SC 1.4.10), and
 *   every row that holds buttons wraps rather than overflowing (SC 1.4.10 again).
 * - Animation is behind prefers-reduced-motion, and forced-colors mode gets real borders so the
 *   bubbles stay distinguishable when our palette is thrown away.
 *
 * @package Studentsbasket_AiChat
 */

.aichat {
    font-size: 14px;
    line-height: 1.5;
}

.aichat-visually-hidden {
    border: 0;
    clip: rect(0 0 0 0);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    white-space: nowrap;
    width: 1px;
}

/* --- Launcher ---------------------------------------------------------------------------- */

/* The launcher and the attribution badge share one fixed row. The badge sits beside a button
   whose label is store configuration and translated, so its width is not knowable in CSS - a flex
   row is what puts the two next to each other without anything having to measure. The row is only
   as wide as its contents, so it never covers anything the launcher alone would not. */
.aichat-dock {
    align-items: center;
    bottom: 20px;
    display: flex;
    gap: 10px;
    position: fixed;
    right: 20px;
    z-index: 9000;
}

.aichat-launcher {
    background: #1b3a6b; /* #ffffff on #1b3a6b = 9.8:1 */
    border: 1px solid #1b3a6b;
    border-radius: 24px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
    color: #ffffff;
    cursor: pointer;
    flex: 0 0 auto;
    font-size: 15px;
    font-weight: 600;
    min-height: 48px;
    padding: 12px 22px;
}

.aichat-launcher:hover,
.aichat-launcher:focus {
    background: #142c52;
}

.aichat-launcher:focus-visible,
.aichat-close:focus-visible,
.aichat-send:focus-visible,
.aichat-end:focus-visible,
.aichat-input:focus-visible,
.aichat-transcript:focus-visible,
.aichat-verify-input:focus-visible,
.aichat-verify-submit:focus-visible,
.aichat-verify-cancel:focus-visible,
.aichat-verify-resend:focus-visible,
.aichat-verify-open:focus-visible,
.aichat-contact-input:focus-visible,
.aichat-contact-submit:focus-visible,
.aichat-contact-skip:focus-visible,
.aichat-issue-select:focus-visible,
.aichat-issue-submit:focus-visible,
.aichat-issue-skip:focus-visible,
.aichat-suggestion:focus-visible,
.aichat-callback-confirm:focus-visible,
.aichat-callback-other:focus-visible,
.aichat-callback-decline:focus-visible,
.aichat-callback-save:focus-visible,
.aichat-callback-cancel:focus-visible,
.aichat-callback-input:focus-visible {
    outline: 3px solid #0b57d0;
    outline-offset: 2px;
}

/* Older engines without :focus-visible still get a ring rather than nothing. */
.aichat-launcher:focus,
.aichat-close:focus,
.aichat-send:focus,
.aichat-end:focus,
.aichat-input:focus,
.aichat-transcript:focus,
.aichat-verify-input:focus,
.aichat-verify-submit:focus,
.aichat-verify-cancel:focus,
.aichat-verify-resend:focus,
.aichat-verify-open:focus,
.aichat-contact-input:focus,
.aichat-contact-submit:focus,
.aichat-contact-skip:focus,
.aichat-issue-select:focus,
.aichat-issue-submit:focus,
.aichat-issue-skip:focus,
.aichat-suggestion:focus,
.aichat-callback-confirm:focus,
.aichat-callback-other:focus,
.aichat-callback-decline:focus,
.aichat-callback-save:focus,
.aichat-callback-cancel:focus,
.aichat-callback-input:focus {
    outline: 3px solid #0b57d0;
    outline-offset: 2px;
}

.aichat-launcher-label {
    white-space: nowrap;
}

/* The launcher stays put while the panel is open so the customer has one obvious way back out,
   and so the control that moved focus is still where focus returns to. */
.aichat-open .aichat-dock {
    bottom: 20px;
}

/* --- Attribution badge ------------------------------------------------------------------- */

/* Shown only while the panel is open, and only ever as text - there is no link here, so nothing
   on it can take a customer off the store in the middle of a question. It is aria-hidden in the
   markup for the same reason it is small: it is branding, and announcing it ahead of the greeting
   every time the panel opens would put it in front of the thing the customer came for. */
.aichat-badge {
    background: #ffffff;
    border: 1px solid #c4c9d4;
    border-radius: 14px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
    color: #45494f; /* 8.6:1 on #ffffff */
    flex: 0 1 auto;
    font-size: 11px;
    line-height: 1.4;
    margin: 0;
    /* Never pushes the launcher off the edge on a narrow viewport: the badge gives way first. */
    overflow: hidden;
    padding: 5px 10px;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.aichat-badge[hidden] {
    display: none;
}

/* --- Panel ------------------------------------------------------------------------------- */

.aichat-panel {
    background: #ffffff;
    border: 1px solid #c4c9d4;
    border-radius: 8px;
    bottom: 80px;
    box-shadow: 0 4px 24px rgba(0, 0, 0, 0.22);
    display: flex;
    flex-direction: column;
    max-height: 70vh;
    position: fixed;
    right: 20px;
    /* Must stay px - see the note at the top of this file about the root font size on this store.
       The max-width keeps the panel inside the viewport between 481px and 400px, the band where the
       small-screen rule below has not taken over yet. */
    max-width: calc(100vw - 40px);
    width: 360px;
    z-index: 9001;
}

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

.aichat-panel-header {
    align-items: center;
    background: #1b3a6b;
    border-radius: 8px 8px 0 0;
    color: #ffffff;
    display: flex;
    justify-content: space-between;
    padding: 10px 8px 10px 16px;
}

.aichat-panel-title {
    color: #ffffff;
    font-size: 16px;
    font-weight: 600;
    margin: 0;
}

.aichat-close {
    background: transparent;
    border: 1px solid transparent;
    border-radius: 4px;
    color: #ffffff;
    cursor: pointer;
    font-size: 22px;
    line-height: 1;
    min-height: 44px;
    min-width: 44px;
    padding: 0;
}

.aichat-close:hover,
.aichat-close:focus {
    background: #142c52;
    border-color: #ffffff;
}

.aichat-close-mark {
    display: block;
}

/* --- Transcript -------------------------------------------------------------------------- */

.aichat-transcript {
    flex: 1 1 auto;
    min-height: 180px;
    overflow-y: auto;
    padding: 12px 16px;
}

/* While a form is open over the transcript, the TRANSCRIPT is what gives way, and the FORM
   becomes the part of the panel that flexes.

   The panel is capped at 70vh, and header + a 180px transcript + a ~300px form + composer +
   footer does not fit inside that on a 900px screen - without this the composer and the footer
   are pushed out through the bottom of the panel and off the page, which is the one control the
   customer needs to get back out of the form. The transcript is the right thing to shrink: it
   scrolls, and what it holds has already been read. Everything else in the panel is a control.

   Swapping which element carries flex-grow is the half that matters and the half that is easy to
   miss. Leaving the transcript growing and the form merely shrinkable looks right at 900px and
   collapses the form to a 25px sliver at 500px - measured - because free space goes to the
   transcript first and the form absorbs every pixel of the shortfall. The customer is being asked
   to fill the form in, so the form is what the spare height belongs to.

   Driven by a class the widget sets rather than by :has(), so it behaves the same on an engine
   that does not support it - and the class costs nothing, because a form that never opened
   cannot overflow anything. */
/* A form open in the panel is allowed a taller panel than a transcript is. 70vh is the right cap
   for reading a conversation; on a 700px-tall laptop it leaves the "Start chatting" button 69px
   below the fold of its own scroll box - measured - which is the one control the customer has to
   reach. The extra tenth is enough for the whole form on every viewport above 760px, and the
   panel still stops short of both the launcher below it and the top of the screen. */
.aichat-form-open .aichat-panel {
    max-height: 80vh;
}

.aichat-form-open .aichat-transcript {
    /* Gives way three times faster than the form does, so a squeeze lands here first. */
    flex: 0 3 auto;
    max-height: 90px;
    min-height: 0;
}

.aichat-form-open .aichat-contact,
.aichat-form-open .aichat-verify {
    flex: 1 1 auto;
    max-height: none;
    min-height: 0;
}

/* The pre-chat form has the panel to itself: no transcript above it until it has been answered.
   The rule above shrinks the transcript to 90px for a form opened over it, which is right for the
   order-confirmation form - that one opens mid-conversation and the transcript behind it is the
   conversation the customer is confirming an order about. It is wrong for this one. The pre-chat
   form comes before there is anything to read, so a greeting above it is not context, it is an
   invitation to answer in the composer underneath instead of in the form.

   display:none rather than visibility or opacity: the transcript is a live region, and one that is
   merely transparent still announces, so a screen reader would read the greeting out over the top
   of a form asking for an email address. The greeting is held back by the browser side until this
   rule stops applying - see flushGreeting in chat.js - so it is announced when it appears. */
.aichat-contact-open .aichat-transcript {
    display: none;
}

/* ...and the composer goes with it, for the same reason and one more. The paragraph above says a
   greeting over an unanswered form invites the customer to type underneath it instead of in the
   form; an empty message box sitting under that form does not merely invite it, it is the thing
   being invited into. The browser side already refuses to send from it while the form is up - see
   contactOpen in applyComposerState - so leaving it on screen offers a control that silently does
   nothing, which reads as a broken panel rather than as a sequence.

   display:none and not the [hidden] attribute. .aichat-composer is display:flex, and a declared
   display beats the user agent's [hidden] rule on specificity - the markup convention elsewhere in
   this file is to pair every such element with its own [hidden] companion. Here the composer is not
   hidden by a state of its own: it is hidden because the pre-chat form is up, which is exactly what
   this class already says, so it hangs off the same class as the transcript above rather than
   inventing a second switch for one condition.

   Two of the three things in the footer go with it, listed below - "End chat" is the one that
   stays. */
.aichat-contact-open .aichat-composer,
/* "You are chatting with an assistant. Ask for a person at any time." describes a conversation,
   and at this point there is not one yet - it is a sentence about the thing the customer is still
   being asked whether to begin. It comes back with the composer the moment the form is answered,
   which is when it starts being true. Safe to take off screen: it is a plain paragraph, not a live
   region, and nothing in the markup points aria-describedby at it. */
.aichat-contact-open .aichat-footnote,
/* ...and so does "Confirm an order", which offers a step through a conversation that has not
   started. It is only ever unhidden by the same start response that opened this form, and the only
   way to reach the confirmation form is this button, so hiding it cannot interrupt a form already
   in progress or strand focus: openContact is reached from start alone, before the customer has
   touched the footer. */
.aichat-contact-open .aichat-verify-open {
    display: none;
}

/* With the sentence gone, so is the flex item that was holding "End chat" over to the right -
   space-between puts a lone child at the start of the row. Without this the button sits on the
   left while the form is up and then jumps across the panel the instant it is answered. */
.aichat-contact-open .aichat-panel-footer {
    justify-content: flex-end;
}

.aichat-message {
    border-radius: 8px;
    margin-bottom: 10px;
    max-width: 92%;
    padding: 8px 12px;
}

.aichat-message-author {
    display: block;
    font-size: 12px;
    font-weight: 600;
    margin-bottom: 2px;
}

.aichat-message-body {
    /* A message is plain text, and a model answer or a pasted order reference can be one long
       unbroken string. Both of these are needed or that string widens the panel. */
    margin: 0;
    overflow-wrap: break-word;
    white-space: pre-wrap;
    word-break: break-word;
}

.aichat-message-customer {
    background: #e7eef9;
    color: #1a1a1a; /* 14.6:1 */
    margin-left: auto;
}

.aichat-message-customer .aichat-message-author {
    color: #1b3a6b; /* 7.4:1 on #e7eef9 */
}

.aichat-message-assistant {
    background: #f2f3f5;
    color: #1a1a1a; /* 15.3:1 */
}

.aichat-message-assistant .aichat-message-author {
    color: #45494f; /* 7.6:1 on #f2f3f5 */
}

/* A reply from a colleague is marked out, because "a person is answering you now" is the single
   most useful thing the transcript can tell a customer. */
.aichat-message-agent {
    background: #fff5e6;
    border-left: 4px solid #a35a00;
    color: #1a1a1a;
}

.aichat-message-agent .aichat-message-author {
    color: #7a4200; /* 6.9:1 on #fff5e6 */
}

/* System notes are the widget's own words - a turn ceiling, a handover. Quieter than a real turn
   but still full-contrast text, since a greyed-out note is the one a customer will not read. */
.aichat-message-system {
    background: #ffffff;
    border: 1px dashed #9aa0ab;
    color: #35383d; /* 10.4:1 */
    font-style: italic;
    max-width: 100%;
}

/* In flight. Deliberately not a spinner and not a fade below 1 - this is the customer's own words
   and they must stay readable while they are being sent. */
.aichat-message-sending {
    opacity: 0.85;
}

/* --- Status region ----------------------------------------------------------------------- */

.aichat-status {
    color: #35383d; /* 10.4:1 */
    font-size: 13px;
    margin: 0;
    padding: 0 16px 6px;
}

/* Collapsed while empty, but never hidden and never removed: a live region taken out of the
   accessibility tree stops announcing what is put into it. */
.aichat-status:empty {
    display: none;
}

.aichat-status-error {
    color: #8b1a1f; /* 7.5:1 on white, and not colour alone - the copy itself says what went wrong */
    font-weight: 600;
}

/* --- Pre-chat contact form --------------------------------------------------------------- */

/* Same place in the panel as the confirmation form below - between the transcript and the
   composer rather than floating over them - but with the transcript hidden while it is up, so the
   panel holds one thing to do and nothing to read past. The composer stays in place and disabled
   rather than being hidden: a text box that vanishes and comes back is harder to follow than one
   that is visibly not ready yet, and it is the thing the customer is going to use next. */
.aichat-contact {
    background: #f7f8fa;
    border-top: 1px solid #e0e3e9;
    /* Shrinks and scrolls rather than growing the panel, for the viewport short enough that even
       a collapsed transcript is not enough - a phone in landscape, or a 400% zoom. */
    flex: 0 1 auto;
    max-height: 60vh;
    min-height: 0;
    overflow-y: auto;
    padding: 12px 16px;
}

.aichat-contact[hidden] {
    display: none;
}

.aichat-contact-form {
    margin: 0;
}

.aichat-contact-title {
    color: #1a1a1a; /* 14.6:1 on #f7f8fa */
    font-size: 14px;
    font-weight: 600;
    margin: 0 0 6px;
}

.aichat-contact-intro {
    color: #35383d; /* 9.9:1 on #f7f8fa */
    font-size: 12px;
    margin: 0 0 10px;
}

/* Visible labels, not placeholders - see the note on the confirmation form's labels below. */
.aichat-contact-label {
    color: #1a1a1a;
    display: block;
    font-size: 12px;
    font-weight: 600;
    margin: 0 0 4px;
}

/* "(optional)" is said in words rather than left to the absence of an asterisk. Which fields are
   required has to be readable without comparing one label against another (SC 3.3.2). */
.aichat-contact-optional {
    color: #45494f; /* 8.6:1 on #f7f8fa */
    font-weight: 400;
}

.aichat-contact-input {
    border: 1px solid #767b85; /* 4.4:1 on #f7f8fa */
    border-radius: 6px;
    box-sizing: border-box;
    color: #1a1a1a;
    display: block;
    font-family: inherit;
    font-size: 14px;
    margin: 0 0 10px;
    min-height: 44px;
    padding: 10px;
    width: 100%;
}

/* Why the address is being asked for, next to the field asking for it. A customer handing over an
   email on a storefront is owed the reason at the point of handing it over, not in a policy. */
.aichat-contact-note {
    color: #45494f;
    font-size: 11px;
    margin: -4px 0 10px;
}

.aichat-contact-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.aichat-contact-submit {
    background: #1b3a6b;
    border: 1px solid #1b3a6b;
    border-radius: 6px;
    color: #ffffff;
    cursor: pointer;
    font-size: 13px;
    font-weight: 600;
    min-height: 44px;
    padding: 10px 14px;
}

.aichat-contact-submit:hover,
.aichat-contact-submit:focus {
    background: #142c52;
}

.aichat-contact-submit:disabled {
    background: #6b7280;
    border-color: #6b7280;
    cursor: default;
}

.aichat-contact-skip {
    background: transparent;
    border: 1px solid #767b85;
    border-radius: 6px;
    color: #35383d;
    cursor: pointer;
    font-size: 12px;
    min-height: 44px;
    padding: 8px 12px;
    white-space: nowrap;
}

.aichat-contact-skip:hover,
.aichat-contact-skip:focus {
    background: #eceef2;
    border-color: #35383d;
}

.aichat-contact-skip[hidden] {
    display: none;
}

.aichat-contact-status {
    color: #35383d;
    font-size: 12px;
    margin: 8px 0 0;
}

/* Collapsed when there is nothing to say, so the form does not carry a permanent blank line. */
.aichat-contact-status:empty {
    margin: 0;
}

.aichat-contact-status-error {
    color: #8b1a1f; /* 7.5:1 on #f7f8fa, and the copy says what is wrong - never colour alone */
    font-weight: 600;
}

/* --- What the question is about ---------------------------------------------------------- */

/* The same place in the panel as the two forms - between the transcript and the composer - but
   deliberately NOT treated like them. This stage leaves the transcript on screen, because by the
   time it appears the greeting is in there and the dropdown is the first question the assistant
   asks; hiding the greeting to ask it would be asking a question with nobody having said hello.
   And it is one control tall, so it does not need the transcript's height the way a four-field
   form does. That is why it does not set .aichat-form-open. */
.aichat-issue {
    background: #f7f8fa;
    border-top: 1px solid #e0e3e9;
    /* Shrinks and scrolls rather than growing the panel, as the forms do - for the viewport short
       enough that even one control is a squeeze. */
    flex: 0 1 auto;
    max-height: 40vh;
    min-height: 0;
    overflow-y: auto;
    padding: 12px 16px;
}

.aichat-issue[hidden] {
    display: none;
}

/* WHILE THE DROPDOWN IS UP, THE TRANSCRIPT IS WHAT GIVES WAY - not the stage.

   The note above is right that this stage does not need the transcript's height the way a
   four-field form does, and wrong about what follows from it. The transcript holds a 180px floor
   plus its padding - 204px - and the stage was the only flexible item left in the column, so the
   stage absorbed every pixel of a squeeze on its own. Measured on the shipped stylesheet: the
   panel needs 579px for header + transcript + dropdown + composer + footer, and the 70vh cap only
   allows that from a 827px-tall viewport upwards. Below that the stage scrolls inside itself with
   "Continue" under the fold - 30px under it on a 1366x768 laptop, 78px at 1280x700, and at
   1280x620 the dropdown itself is clipped. The customer picks a reason and then has nothing in
   front of them that says what to do next, which is exactly the report.

   So the transcript gets the same treatment it already gets under a form, for the same reason and
   with the same numbers: 90px is enough for the whole greeting, it has been read, and it scrolls.
   The stage keeps its natural height instead. */
.aichat-issue-open .aichat-transcript {
    flex: 0 3 auto;
    min-height: 0;
    /* 114px and border-box is the SAME visible window as the 90px content-box cap the form-open
       rule above uses - 90px of greeting plus the 12px of padding top and bottom. Written this way
       round because the box is also the one being asked to collapse on a short screen, and on
       content-box a shrink to zero still leaves its padding standing: with max-height: 90px here
       the greeting lost its last line to a 22px scroll on every screen, measured. */
    box-sizing: border-box;
    max-height: 114px;
}

/* The stage shrinks LAST rather than first. flex-shrink is proportional, not ordered, so leaving
   the stage at 1 hands it a share of every squeeze even with the transcript collapsible - and a
   share is all it takes, because "Continue" is the bottom 44px of it.

   Its own max-height: 40vh and overflow-y: auto above are left in place as the backstop. They are
   what stops this refusing to shrink from pushing the composer and "End chat" out through the
   bottom of the panel if an admin ever authors a label long enough to wrap the stage past that
   cap - the stage scrolls in that case, the panel stays whole. */
/* 370px is the floor, and the figure is measured rather than chosen. The panel's fixed furniture
   is 224px - header, composer, footer - and the stage is 151px, so 375px is what the panel cannot
   give way on once the transcript above it has collapsed to nothing. Under that, refusing to
   shrink would push "End chat" out through the bottom of the panel instead - worse than a clipped
   button, because it is the only way out of the panel. Below 370px the stage goes back to taking
   its share, as it does today.

   The floor used to be 490px, because a transcript squeezed to nothing still cost its own 24px of
   padding and a box cannot shrink past its padding. The rule below drops that padding for the
   length of this stage, which is what buys the other 120px. */
@media (min-height: 370px) {
    .aichat-issue-open .aichat-issue {
        flex-shrink: 0;
    }
}

/* The last 24px, and the only thing standing between a clipped "Continue" and a clean one on a
   laptop. A collapsed box keeps its padding, so on a short screen the transcript was still
   charging the column 24px for a greeting it was showing none of. Scoped to the band that
   actually needs it - above 490px the transcript has its full 114px window and its padding is
   doing real work.

   Measured across every viewport height from 360px to 1080px, at 1280px, 844px and 390px wide:
   "Continue" is fully visible at every height from 370px up, the footer never leaves the panel,
   and the greeting never collapses to nothing. On the stylesheet that ships today the button is
   clipped at 44 of those 73 heights, by as much as 115px, and between 460px and 630px the footer
   falls out of the panel with it. */
@media (max-height: 489px) {
    .aichat-issue-open .aichat-transcript {
        padding-bottom: 0;
        padding-top: 0;
    }
}

/* And the panel is allowed the room, as it already is for a form. Expressed against the viewport
   rather than as a percentage of it because the panel sits 80px off the bottom: 85vh would put the
   header - and the close button in it - off the top of the screen below 533px, which is a worse
   bug than the one being fixed. Subtracting the offset the panel already stands on - 80px - plus
   its own 1px border top and bottom, which max-height does not count because this panel is
   content-box, means the header cannot leave the top of the screen at any height. Without those
   two pixels it does, by exactly two: measured. The cap only binds below about 650px; above that
   the panel is shorter than it and nothing changes.

   Paired with the short-viewport rule at the foot of this file, which keeps its 100vh on a
   landscape phone - without that pairing this would override it and cost 100px there. */
.aichat-issue-open .aichat-panel {
    max-height: calc(100vh - 82px);
}

.aichat-issue-form {
    margin: 0;
}

.aichat-issue-title {
    color: #1a1a1a; /* 14.6:1 on #f7f8fa */
    font-size: 14px;
    font-weight: 600;
    margin: 0 0 8px;
}

/* A native select, styled only as far as the box around it. The arrow, the open list and the
   keyboard behaviour are left to the platform on purpose: an appearance:none select needs the
   whole listbox rebuilt in JavaScript to stay usable, and the rebuilt ones are reliably worse on a
   phone and with a screen reader than the one the operating system already has. */
.aichat-issue-select {
    background: #ffffff;
    border: 1px solid #767b85; /* 4.4:1 on #f7f8fa */
    border-radius: 6px;
    box-sizing: border-box;
    color: #1a1a1a;
    display: block;
    font-family: inherit;
    font-size: 14px;
    margin: 0 0 10px;
    /* 44px to match every other target in the panel - comfortably past the 24px floor of SC
       2.5.8, and the height a thumb actually hits. */
    min-height: 44px;
    padding: 10px;
    width: 100%;
}

.aichat-issue-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.aichat-issue-submit {
    background: #1b3a6b;
    border: 1px solid #1b3a6b;
    border-radius: 6px;
    color: #ffffff;
    cursor: pointer;
    font-size: 13px;
    font-weight: 600;
    min-height: 44px;
    padding: 10px 14px;
}

.aichat-issue-submit:hover,
.aichat-issue-submit:focus {
    background: #142c52;
}

.aichat-issue-submit:disabled {
    background: #6b7280;
    border-color: #6b7280;
    cursor: default;
}

.aichat-issue-skip {
    background: transparent;
    border: 1px solid #767b85;
    border-radius: 6px;
    color: #35383d;
    cursor: pointer;
    font-size: 12px;
    min-height: 44px;
    padding: 8px 12px;
    white-space: nowrap;
}

.aichat-issue-skip:hover,
.aichat-issue-skip:focus {
    background: #eceef2;
    border-color: #35383d;
}

.aichat-issue-skip[hidden] {
    display: none;
}

.aichat-issue-status {
    color: #35383d; /* 9.9:1 on #f7f8fa */
    font-size: 12px;
    margin: 8px 0 0;
}

.aichat-issue-status:empty {
    margin: 0;
}

.aichat-issue-status-error {
    color: #8b1a1f; /* 7.5:1 on #f7f8fa, and the copy says what is wrong - never colour alone */
    font-weight: 600;
}

/* --- Mid-chat suggestions ---------------------------------------------------------------- */

/* Chips under the last answer, above the composer. Not inside the transcript: they are controls
   rather than something anybody said, so in there they would scroll away with the history and be
   announced as a turn by a screen reader.

   No top border and the panel's own background rather than the forms' grey. The forms are stages
   that hold the chat up; these are an offer sitting with the reply they belong to, and a grey band
   with a rule above it reads as the conversation having stopped. */
.aichat-suggestions {
    flex: 0 0 auto;
    padding: 0 16px 10px;
}

.aichat-suggestions[hidden] {
    display: none;
}

.aichat-suggestions-label {
    color: #45494f; /* 8.6:1 on #ffffff */
    font-size: 12px;
    margin: 0 0 6px;
}

.aichat-suggestions-list {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/* Wrapping, not a horizontal scroller. A row of chips that scrolls sideways hides however many do
   not fit, and the one the customer wants is as likely to be the fifth as the first. Wrapped, the
   whole list is readable at any width and at 400% zoom. */
.aichat-suggestion {
    background: #ffffff;
    border: 1px solid #1b3a6b;
    border-radius: 16px;
    color: #1b3a6b; /* 9.0:1 on #ffffff */
    cursor: pointer;
    font-family: inherit;
    font-size: 13px;
    /* 44px is too tall for a dense row of these and they are not the primary control on screen;
       32px with the padding below still clears SC 2.5.8's 24px minimum with room to spare. */
    min-height: 32px;
    padding: 6px 12px;
    text-align: left;
}

.aichat-suggestion:hover,
.aichat-suggestion:focus {
    background: #eef2f9;
}

/* "Something else" is the way past the list rather than an item on it, so it is quieter than the
   reasons beside it - but it is still a bordered button with a 4.5:1 label, not a text link. */
.aichat-suggestion-other {
    border-color: #767b85;
    color: #35383d; /* 10.4:1 on #ffffff */
}

.aichat-suggestion-other:hover,
.aichat-suggestion-other:focus {
    background: #f1f2f5;
    border-color: #35383d;
}

/* --- Callback number --------------------------------------------------------------------- */

/* The card that turns "a member of the team will be in touch" into a phone call. It sits between
   the transcript and the composer with the suggestion chips, and for the same reasons: it is a
   control rather than something anybody said, so inside the transcript it would scroll away with
   the history and be announced as a turn by a screen reader.

   It keeps the forms' grey and a rule above it, unlike the chips. The chips are an offer about
   the last answer and a grey band there reads as the conversation having stopped; this is a
   decision with three outcomes attached to a case that has already been raised, and it should
   read as a distinct thing to deal with rather than as part of the reply above it.

   The composer stays live underneath - see the note in widget.phtml. That is why there is no
   .aichat-form-open here: nothing about this card holds the chat up. */
.aichat-callback {
    background: #f7f8fa;
    border-top: 1px solid #e0e3e9;
    /* Shrinks and scrolls rather than growing the panel, as the other stages do - the backstop
       for a viewport short enough that even this is a squeeze. */
    flex: 0 1 auto;
    max-height: 45vh;
    min-height: 0;
    overflow-y: auto;
    padding: 12px 16px;
}

.aichat-callback[hidden] {
    display: none;
}

/* WHILE THE CARD IS UP, THE TRANSCRIPT IS WHAT GIVES WAY - not the card.

   Same failure as the reason dropdown had: the transcript holds a 180px floor plus its padding,
   and a stage that is the only flexible item left in the column absorbs every pixel of a squeeze
   on its own. Here that would clip "No, email me instead" - the only control on the card that
   ends the question - which is the worse half of the same bug.

   But NOT the 114px window the greeting gets under a form. By the time this card appears the
   transcript holds the conversation the customer is actually having, and the message that
   promised them a call is the last line in it. Cropping that to three lines to ask where to ring
   them would be asking about a promise they can no longer read. So the floor is dropped and the
   transcript is merely made the first thing to give way - it keeps whatever height is left, which
   on any ordinary screen is most of what it had. */
.aichat-callback-open .aichat-transcript {
    /* Gives way three times faster than the card does, so a squeeze lands here first. */
    flex: 0 3 auto;
    min-height: 0;
}

/* The card shrinks LAST rather than first - but ONLY from the height at which it actually fits.
   flex-shrink is proportional and not ordered, so leaving it at 1 hands the card a share of every
   squeeze even with the transcript collapsible, and a share is all it takes: the buttons are the
   bottom 44px of it.

   620px, and the figure is measured rather than chosen. The card is 281px with the number box
   open, the panel's fixed furniture is 206px - header, composer, footer - and the panel is capped
   at the viewport less 82px, so 620px is the shortest screen on which all of that fits at once.

   Refusing to shrink BELOW that floor is worse than the bug it fixes, and this was measured the
   wrong way round first: at a 400px floor the card held its full height from 400px to 610px and
   pushed the FOOTER out through the bottom of the panel instead - by as much as 134px, with "End
   chat" off the screen entirely between 400px and 470px. That is the only way out of the panel,
   so below the floor the card goes back to taking its share and scrolls inside its own 45vh cap,
   which is what overflow-y above is for.

   Swept at every viewport height from 360px to 1080px at 1280px, 844px and 390px wide, in all
   three states the card has: the footer never leaves the panel and "End chat" is never off
   screen at any height. */
@media (min-height: 620px) {
    .aichat-callback-open .aichat-callback {
        flex-shrink: 0;
    }
}

/* The last 24px, and what buys the floor above. A collapsed box keeps its padding, so on a short
   screen the transcript was still charging the column 24px for a conversation it was showing none
   of - which is 24px the card could have had. Scoped to the band that needs it: above the floor
   the transcript has real height and its padding is doing real work.

   Worth 24px of card on every height below the floor - the worst-case scroll inside the card goes
   from 240px to 216px with it, measured. */
@media (max-height: 619px) {
    .aichat-callback-open .aichat-transcript {
        padding-bottom: 0;
        padding-top: 0;
    }
}

/* The panel is allowed the room, exactly as it is for a form and for the dropdown. Expressed
   against the viewport rather than as a percentage of it because the panel sits 80px off the
   bottom: see the identical note on .aichat-issue-open .aichat-panel for why the 82px matters. */
.aichat-callback-open .aichat-panel {
    max-height: calc(100vh - 82px);
}

.aichat-callback-title {
    color: #1a1a1a; /* 14.6:1 on #f7f8fa */
    font-size: 14px;
    font-weight: 600;
    margin: 0 0 6px;
}

/* The number is the thing being checked, so it is the largest text on the card and it is spaced.
   Not a monospace face - a customer reads their own number as a shape, and a figure face they do
   not recognise makes them check it digit by digit instead. */
.aichat-callback-number {
    color: #1a1a1a; /* 14.6:1 on #f7f8fa */
    font-size: 17px;
    font-weight: 600;
    letter-spacing: 0.5px;
    margin: 0 0 10px;
}

.aichat-callback-number[hidden] {
    display: none;
}

/* A column rather than a row. These are three sentences, not three words, and side by side they
   wrap into each other at panel width; stacked, each one is a full-width target and the order
   reads as what it is - yes, something else, no. */
.aichat-callback-actions {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* A DECLARED display BEATS the browser's own [hidden] rule, so hiding the three choices from
   JavaScript needs this and not only the attribute. Without it "Use a different number" opens
   the box UNDERNEATH the three buttons it was supposed to replace - measured: the card goes from
   257px to 430px, and on a 1280x700 laptop "Call me on this number" sits 78px below the fold of
   its own scroll box, which is the report that opened this ticket's last fix. */
.aichat-callback-actions[hidden] {
    display: none;
}

.aichat-callback-confirm,
.aichat-callback-other,
.aichat-callback-decline,
.aichat-callback-save,
.aichat-callback-cancel {
    border-radius: 6px;
    cursor: pointer;
    font-family: inherit;
    font-size: 14px;
    /* 44px, because unlike the chips these are the primary controls on screen and one of them
       commits a phone number. SC 2.5.5. */
    min-height: 44px;
    padding: 10px 14px;
    text-align: center;
    width: 100%;
}

/* The expected answer, and the only filled button on the card. */
.aichat-callback-confirm,
.aichat-callback-save {
    background: #1b3a6b;
    border: 1px solid #1b3a6b;
    color: #ffffff; /* 10.0:1 on #1b3a6b */
    font-weight: 600;
}

.aichat-callback-confirm:hover,
.aichat-callback-confirm:focus,
.aichat-callback-save:hover,
.aichat-callback-save:focus {
    background: #142c52;
}

/* The two ways past it. Outlined rather than filled so there is one obvious answer, but still
   bordered buttons with a 4.5:1 label - never text links, which on a touch screen are a 14px
   target. */
.aichat-callback-other,
.aichat-callback-decline,
.aichat-callback-cancel {
    background: #ffffff;
    border: 1px solid #767b85; /* 4.4:1 on #f7f8fa */
    color: #35383d; /* 10.4:1 on #ffffff */
}

.aichat-callback-other:hover,
.aichat-callback-other:focus,
.aichat-callback-decline:hover,
.aichat-callback-decline:focus,
.aichat-callback-cancel:hover,
.aichat-callback-cancel:focus {
    background: #f1f2f5;
    border-color: #35383d;
}

.aichat-callback-form {
    margin: 0;
}

.aichat-callback-label {
    color: #35383d; /* 10.4:1 on #f7f8fa */
    display: block;
    font-size: 13px;
    font-weight: 600;
    margin: 0 0 4px;
}

.aichat-callback-input {
    background: #ffffff;
    border: 1px solid #767b85;
    border-radius: 6px;
    box-sizing: border-box;
    color: #1a1a1a;
    display: block;
    font-family: inherit;
    font-size: 16px; /* 16px, or iOS zooms the page when the field takes focus */
    margin: 0 0 10px;
    min-height: 44px;
    padding: 10px 12px;
    width: 100%;
}

.aichat-callback-status {
    color: #45494f; /* 8.6:1 on #f7f8fa */
    font-size: 13px;
    margin: 8px 0 0;
}

/* Collapsed when there is nothing to say, so the card does not carry a permanent blank line. */
.aichat-callback-status:empty {
    margin: 0;
}

.aichat-callback-status-error {
    color: #8b1a1f; /* 7.5:1 on #f7f8fa, and the copy says what is wrong - never colour alone */
    font-weight: 600;
}

/* --- Order confirmation ------------------------------------------------------------------ */

/* Sits between the transcript and the composer rather than over them, so the customer can still
   read what the assistant asked while they fill it in. It is a form inside a dialog, not a second
   dialog: stacking one on top of the other would trap a keyboard user between two close buttons. */
.aichat-verify {
    background: #f7f8fa;
    border-top: 1px solid #e0e3e9;
    /* See the note on .aichat-contact above - this form has always had the same overflow, it
       simply had nothing below it on screen to make it obvious. */
    flex: 0 1 auto;
    max-height: 60vh;
    min-height: 0;
    overflow-y: auto;
    padding: 12px 16px;
}

.aichat-verify[hidden] {
    display: none;
}

/* The two steps are separate forms in one panel. No display rule other than the hidden guard -
   setting one would override the browser's [hidden] and leave the code step on screen from the
   start, which is the second form showing before a code has been asked for. */
.aichat-verify-form {
    margin: 0;
}

.aichat-verify-form[hidden] {
    display: none;
}

.aichat-verify-title {
    color: #1a1a1a; /* 14.6:1 on #f7f8fa */
    font-size: 14px;
    font-weight: 600;
    margin: 0 0 6px;
}

.aichat-verify-intro {
    color: #35383d; /* 9.9:1 on #f7f8fa */
    font-size: 12px;
    margin: 0 0 10px;
}

/* Labels are visible, not placeholders. A placeholder vanishes the moment the customer types,
   which SC 3.3.2 rules out for exactly this kind of field - an order number typed half-wrong with
   no label left on screen is unfixable. */
.aichat-verify-label {
    color: #1a1a1a;
    display: block;
    font-size: 12px;
    font-weight: 600;
    margin: 0 0 4px;
}

.aichat-verify-input {
    border: 1px solid #767b85; /* 4.4:1 on #f7f8fa */
    border-radius: 6px;
    box-sizing: border-box;
    color: #1a1a1a;
    display: block;
    font-family: inherit;
    font-size: 14px;
    margin: 0 0 10px;
    min-height: 44px;
    padding: 10px;
    width: 100%;
}

/* The code is read off a screen and typed one character at a time, so it is spaced out and
   tabular - 0 against O and 1 against l is the whole difficulty of entering one. */
.aichat-verify-code {
    font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
    font-size: 18px;
    letter-spacing: 4px;
}

.aichat-verify-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.aichat-verify-submit {
    background: #1b3a6b;
    border: 1px solid #1b3a6b;
    border-radius: 6px;
    color: #ffffff;
    cursor: pointer;
    font-size: 13px;
    font-weight: 600;
    min-height: 44px;
    padding: 10px 14px;
}

.aichat-verify-submit:hover,
.aichat-verify-submit:focus {
    background: #142c52;
}

.aichat-verify-submit:disabled {
    background: #6b7280;
    border-color: #6b7280;
    cursor: default;
}

.aichat-verify-cancel,
.aichat-verify-resend,
.aichat-verify-open {
    background: transparent;
    border: 1px solid #767b85;
    border-radius: 6px;
    color: #35383d;
    cursor: pointer;
    font-size: 12px;
    min-height: 44px;
    padding: 8px 12px;
    white-space: nowrap;
}

.aichat-verify-cancel:hover,
.aichat-verify-cancel:focus,
.aichat-verify-resend:hover,
.aichat-verify-resend:focus,
.aichat-verify-open:hover,
.aichat-verify-open:focus {
    background: #eceef2;
    border-color: #35383d;
}

/* The countdown state. Still full-contrast text: a customer who cannot read why the button is
   refusing them will press it until it works. */
.aichat-verify-resend:disabled {
    background: #eceef2;
    color: #45494f; /* 7.3:1 on #eceef2 */
    cursor: default;
}

.aichat-verify-open[hidden] {
    display: none;
}

/* Same rule as the chat status region: collapsed while empty, never hidden, never removed. */
.aichat-verify-status {
    color: #35383d;
    font-size: 12px;
    margin: 10px 0 0;
}

.aichat-verify-status:empty {
    display: none;
}

.aichat-verify-status-error {
    color: #8b1a1f; /* 7.1:1 on #f7f8fa, and never the only signal - the copy says what is wrong */
    font-weight: 600;
}

/* --- Composer ---------------------------------------------------------------------------- */

.aichat-composer {
    align-items: flex-end;
    border-top: 1px solid #e0e3e9;
    display: flex;
    gap: 8px;
    padding: 10px 16px;
}

.aichat-input {
    border: 1px solid #767b85; /* 4.6:1 against white - a 3:1 border would meet SC 1.4.11 and still
                                  be hard to see, so this is deliberately darker */
    border-radius: 6px;
    color: #1a1a1a;
    flex: 1 1 auto;
    font-family: inherit;
    font-size: 14px;
    min-height: 44px;
    /* A flex item will not shrink below its content width without this, and a textarea's content
       width is its `cols` default of 20 characters - which is what pushes the send button out. */
    min-width: 0;
    padding: 10px;
    resize: vertical;
    width: 100%;
}

.aichat-input:disabled {
    background: #f2f3f5;
    color: #45494f; /* still 7.6:1 - a disabled control the customer cannot read is a dead end */
}

.aichat-send {
    background: #1b3a6b;
    border: 1px solid #1b3a6b;
    border-radius: 6px;
    color: #ffffff;
    cursor: pointer;
    flex: 0 0 auto;
    font-size: 14px;
    font-weight: 600;
    min-height: 44px;
    min-width: 72px;
    padding: 10px 14px;
}

.aichat-send:hover,
.aichat-send:focus {
    background: #142c52;
}

.aichat-send:disabled {
    background: #6b7280;
    border-color: #6b7280;
    cursor: default;
}

/* --- Footer ------------------------------------------------------------------------------ */

/* Wraps, like .aichat-verify-actions above it. This row holds a sentence and up to two buttons
   whose widths are translation-dependent, so there is no width at which it is guaranteed to fit on
   one line - without wrapping, the overflow is silent and lands outside the panel's rounded edge. */
.aichat-panel-footer {
    align-items: center;
    border-top: 1px solid #e0e3e9;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    justify-content: space-between;
    padding: 8px 16px 10px;
}

.aichat-footnote {
    color: #45494f; /* 8.6:1 */
    flex: 1 1 120px;
    font-size: 12px;
    margin: 0;
    /* Shrinks to a sensible wrap, then takes its own line - rather than collapsing to one word per
       line while the buttons beside it keep their full width. */
    min-width: 0;
}

.aichat-end {
    background: transparent;
    border: 1px solid #767b85;
    border-radius: 6px;
    color: #35383d;
    cursor: pointer;
    flex: 0 0 auto;
    font-size: 12px;
    min-height: 44px;
    padding: 8px 12px;
    white-space: nowrap;
}

.aichat-end:hover,
.aichat-end:focus {
    background: #f2f3f5;
    border-color: #35383d;
}

/* --- Small screens ----------------------------------------------------------------------- */

/* Full width rather than a floating card. A 360px panel on a 360px phone leaves the store
   unusable behind it, and the reflow requirement (SC 1.4.10) rules out sideways scrolling. */
@media (max-width: 480px) {
    .aichat-panel {
        border-radius: 0;
        bottom: 0;
        left: 0;
        max-height: 85vh;
        /* Cleared, or the calc() above would hold the panel 40px short of the full width this
           rule exists to give it. */
        max-width: none;
        right: 0;
        width: auto;
    }

    .aichat-open .aichat-dock {
        /* Out of the way of the panel it opened, but still reachable. */
        bottom: auto;
        top: 8px;
    }

    /* At this width the dock is sitting on top of the full-screen panel's own header, and the
       badge would be reading over the assistant's name. The launcher is the control; the badge is
       decoration, so the badge is what goes. */
    .aichat-open .aichat-badge {
        display: none;
    }
}

/* Short viewports - a phone in landscape, or a desktop zoomed to 400%. Without this the composer
   is pushed off the bottom of the panel and the widget cannot be used at all. */
@media (max-height: 450px) {
    /* .aichat-issue-open named here as well, or the two-class rule up in the dropdown section
       outranks this one-class selector and takes 100px off the panel at the height that has
       least of it. */
    .aichat-panel,
    .aichat-issue-open .aichat-panel {
        max-height: 100vh;
    }

    .aichat-transcript {
        min-height: 60px;
    }

    /* At this height the dropdown is competing with the composer for the last 100px. The
       stage is what the customer is being asked to deal with, so the transcript above it
       gives way rather than the stage scrolling inside itself. */
    .aichat-issue {
        max-height: 55vh;
    }

    /* A long list of chips would otherwise fill a landscape phone's whole panel. Scrolls
       vertically inside its own box, which keeps every chip reachable - unlike a sideways
       scroller, which hides however many do not fit. */
    .aichat-suggestions {
        max-height: 96px;
        overflow-y: auto;
    }
}

/* --- User preferences -------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    .aichat-launcher,
    .aichat-panel,
    .aichat-message {
        animation: none !important;
        transition: none !important;
    }
}

/* Windows high contrast and similar modes throw the palette away. Without borders the bubbles all
   become the same surface and the transcript stops being readable as a conversation. */
@media (forced-colors: active) {
    .aichat-panel,
    .aichat-message,
    .aichat-launcher,
    .aichat-send,
    .aichat-end,
    .aichat-close,
    .aichat-input,
    .aichat-verify,
    .aichat-verify-input,
    .aichat-verify-submit,
    .aichat-verify-cancel,
    .aichat-verify-resend,
    .aichat-verify-open,
    .aichat-badge,
    .aichat-contact,
    .aichat-contact-input,
    .aichat-contact-submit,
    .aichat-contact-skip,
    .aichat-issue,
    .aichat-issue-select,
    .aichat-issue-submit,
    .aichat-issue-skip,
    .aichat-suggestion {
        border: 1px solid CanvasText;
    }

    .aichat-message-agent {
        border-left-width: 4px;
    }
}

/* Nothing of the widget belongs in print. */
@media print {
    .aichat {
        display: none;
    }
}
