/* Concierge WEBSITE voice wave — the bars a visitor sees while the bot speaks
 * on a tenant's own public site.  (sfww-)
 *
 * A SEPARATE TOOL from every other wave on the platform. It shares no class,
 * no node and no rule with Forge's chat wave (fjwv-), Forge's slide wave
 * (fjpw-) or the staff-side Concierge wave (sfcw-). The house rule is that two
 * tools never share styling; here it also means a visitor's site can never be
 * affected by a change made for an admin screen. Prefix verified unused across
 * every module before this file was written.
 *
 * ── WHERE THE COLOUR COMES FROM ─────────────────────────────────────────
 * The workspace's own Concierge "Theme Color" setting, which the widget
 * already publishes as --sfaic-theme, with the panel's own background and
 * border tokens around it. That setting is the single source of truth for how
 * this widget looks, so the bars follow it and change with it.
 *
 * Deliberately NOT a Theme Studio card. Theme Studio dresses the admin and
 * SkyForj's own website; its stylesheet is not loaded on a tenant's public
 * site at all, so a card here would both do nothing for a visitor and set up a
 * second place to change one colour. One source of truth, and it is the
 * setting the workspace already has.
 *
 * ── SCOPED ON PURPOSE ───────────────────────────────────────────────────
 * Every rule is prefixed with #sfaic-widget, exactly as the rest of this
 * widget's stylesheet is. This CSS is served onto somebody else's website: an
 * unscoped rule could reach their markup, and that is not ours to touch.
 * No !important anywhere — this widget has none and does not need any.
 */

#sfaic-widget .sfww-strip {
    /* A block of its own in the message column, sitting directly above the
       reply it belongs to. It is NOT laid over the words: on this surface the
       reply types itself out at the workspace's chosen reading pace while the
       voice reads along, and covering it would throw that away. */
    display: flex;
    align-items: center;          /* grow from the middle, like a waveform */
    justify-content: center;
    height: 44px;
    padding: 0 12px;
    box-sizing: border-box;
    border-radius: 14px;
    border: 1px solid var(--sfaic-border);
    background: var(--sfaic-bg);
    color: var(--sfaic-theme);
    /* The message list is a flex column; say what this is rather than be
       stretched to fill it. */
    flex: 0 0 auto;
    /* Nothing here may ever scroll a visitor's page sideways. */
    overflow: hidden;
    max-width: 100%;
}

/* ── the words, while the bars are leading ───────────────────────────────
 *
 * The owner asked on 2026-09-18, having seen it both ways, for this surface to
 * behave like the other three: the words wait until the voice has finished.
 * (Their first choice was to let the reply type out alongside the voice; they
 * changed it after using it. The cost is that the workspace's typing-pace
 * setting has no visible effect while the voice is on — said plainly at the
 * time and accepted.)
 *
 * ⚠ THIS GOES ON THE BUBBLE, AND THE BARS ARE NOT INSIDE THE BUBBLE.
 * Opacity applies to everything inside an element, so bars placed inside a
 * faded bubble cannot be seen — that exact mistake made the staff-side bars
 * invisible earlier today. Here the strip is a SIBLING of the bubble, sitting
 * above it in the message column, so fading the bubble hides only the words.
 * If anyone ever moves the strip inside the bubble, this has to change with it.
 *
 * Opacity, not `display` or `visibility`: it keeps the bubble exactly the size
 * it already is, so nothing shifts, and it leaves the words in the page and in
 * the accessibility tree, so a visitor using a screen reader still gets the
 * reply while the bars are showing. */
#sfaic-widget .sfww-hushed {
    opacity: 0;
}

/* The words coming back. Gentle rather than abrupt, matching the pace the
   owner settled on for the slides. */
#sfaic-widget .sfww-reveal {
    animation: sfww-fade-in .82s ease-out both;
}

@keyframes sfww-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* ── the waiting dots, before the voice starts ───────────────────────────
 *
 * Our own three dots, in our own strip, with our own classes. They stand in
 * for the widget's own waiting mark, which lives inside the reply bubble and is
 * therefore hidden along with the words. The owner asked for the sequence
 * plainly: dots while it thinks, bars while it talks, words afterwards.
 *
 * Both the dots and the bars are always present in the strip; only which one
 * is shown changes, so the swap costs nothing and nothing is rebuilt. */
#sfaic-widget .sfww-dots {
    display: none;
    align-items: center;
    justify-content: center;
    gap: 6px;
}

#sfaic-widget .sfww-thinking .sfww-dots { display: flex; }
#sfaic-widget .sfww-thinking .sfww-bars { display: none; }

#sfaic-widget .sfww-dots i {
    display: block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentColor;
    opacity: .35;
    animation: sfww-dot 1.05s ease-in-out infinite;
}

#sfaic-widget .sfww-dots i:nth-child(2) { animation-delay: .15s; }
#sfaic-widget .sfww-dots i:nth-child(3) { animation-delay: .3s; }

@keyframes sfww-dot {
    0%, 60%, 100% { opacity: .30; transform: translateY(0); }
    30%           { opacity: 1;   transform: translateY(-3px); }
}

/* ── the bars' row ───────────────────────────────────────────────────── */

#sfaic-widget .sfww-bars {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 3px;
    width: 100%;
    height: 100%;
    overflow: hidden;
}

#sfaic-widget .sfww-bar {
    display: block;
    flex: 0 0 auto;
    width: 4px;
    /* Per cent of the strip's own height, which is a set number above, so
       this resolves without depending on anything outside the widget. */
    height: 12%;
    min-height: 3px;
    border-radius: 999px;
    background: currentColor;     /* the workspace's colour, nothing else */
    /* Short, so a bar keeps up with a voice instead of lagging behind it. */
    transition: height .08s linear;
    will-change: height;
}

/* ── when movement is not wanted ─────────────────────────────────────────
 * A visitor who has asked their device for less motion gets one still, even
 * shape instead — the script stops writing heights, so this is simply what
 * they rest at. Still honest: the strip only ever appears while there really
 * is a voice playing. The same rule applies when the sound cannot be measured
 * at all, which is the case for a voice built on the visitor's own device. */
@media (prefers-reduced-motion: reduce) {
    #sfaic-widget .sfww-bar { transition: none; height: 30%; }
    /* The words return at once rather than fading. */
    #sfaic-widget .sfww-reveal { animation: none; }
    /* The dots stay, evenly, rather than bouncing: a visitor still needs to
       know something is happening. */
    #sfaic-widget .sfww-dots i { animation: none; opacity: .55; }
}

#sfaic-widget .sfww-still .sfww-bar { transition: none; height: 30%; }

/* A narrow phone: the panel goes full width, so keep the strip a little
   shorter and the bars a little thinner rather than let it dominate. */
@media (max-width: 480px) {
    #sfaic-widget .sfww-strip { height: 38px; }
    #sfaic-widget .sfww-bars { gap: 2px; }
    #sfaic-widget .sfww-bar { width: 3px; }
    #sfaic-widget .sfww-dots i { width: 6px; height: 6px; }
}
