/* ============================================================================
   FEEDBACK

   A topbar icon and the panel it opens. The icon lives in the page
   chrome (feedback/trigger.html, rendered once for the navbar and once
   for the mobile logo header); everything
   it opens lives in a fixed overlay that feedback.js parks under
   whichever of the two is on screen.

   The overlay is a zero-sized point at that anchor — the trigger's
   horizontal centre, just below it — and the panel and the right-click
   menu are placed against it. `--feedback-tail-x` is the distance from
   a surface's left edge back to that centre, so the panel's tail keeps
   pointing at the icon even when the surface has been pushed left to
   stay on screen.

   The panel is one flat surface — no header band, no boxed fields. The
   only lines drawn are the panel's own edge and a single hairline above
   the action row; everything else is separated by space. color comes
   from tokens, so both themes follow.

   State lives on `html`, not on the overlay, because the trigger is
   outside it: `.feedback-open` and `[data-feedback-draft]`.

   Stacking: above page content and the drawer backdrop (1039), below
   Bootstrap modals (1050), so a dialog still covers the panel.
   ============================================================================ */

.feedback-widget {
    /* Anchor, in viewport pixels, written by feedback.js. The fallbacks are
       only what the first frame uses, before it has measured anything. */
    --feedback-anchor-x: 50vw;
    --feedback-anchor-y: 62px;
    --feedback-tail-x: 22px;
    /* How far the surfaces stay clear of the viewport edges. */
    --feedback-panel-inset: 16px;
    --feedback-pad: 18px;
    --feedback-body-gutter: 8px; /* room for Send's shadow — see .feedback-panel */
    /* The widget's one blue fill: the chosen category chip and Send both wear
       it, so they read as the same control in two places. */
    --feedback-accent-fill: linear-gradient(
        180deg,
        rgba(var(--bs-primary-rgb), 0.28),
        rgba(var(--bs-primary-rgb), 0.16)
    );
    --feedback-accent-shadow:
        0 2px 6px rgba(0, 0, 0, 0.45),
        0 1px 0 rgba(255, 255, 255, 0.06) inset;
    position: fixed;
    left: var(--feedback-anchor-x);
    top: var(--feedback-anchor-y);
    /* A point, not a box: it must not intercept clicks on the page under it,
       and the surfaces it anchors are all absolutely positioned. */
    width: 0;
    height: 0;
    z-index: 1045;
    font-family: var(--font-family-base);
}

/* --- The topbar trigger ---------------------------------------------
   Chrome and color come from .btn-ghost, like every other topbar icon.
   What is added here is the one thing only this button says: an unsent
   draft.
   -------------------------------------------------------------------- */

.feedback-trigger {
    font-size: 1.05rem;
}

/* The mobile mount sits in the logo header, whose children are ordered:
   the sidenav hamburger is 1 and the topbar "more" toggle is 3. */
.logo-header .feedback-trigger {
    order: 2;
    margin-left: 0.25rem;
}

/* An unsent draft is worth a mark on the icon — it is the only clue left
   once the panel is closed and the user has navigated away. The ring is
   the topbar's own color, so the dot reads as sitting on the chrome. */
html[data-feedback-draft="true"] .feedback-trigger::after {
    content: "";
    position: absolute;
    top: 7px;
    right: 7px;
    width: 10px;
    height: 10px;
    border: 2px solid var(--chrome-surface);
    border-radius: 50%;
    background: rgb(var(--color-orange-rgb));
}

/* --- Right-click menu ------------------------------------------------
   Placed at the pointer by `openContextMenu()`, so it takes no part in
   the widget's flex column despite sitting inside it.
   -------------------------------------------------------------------- */

.feedback-menu {
    position: fixed;
    z-index: 1046; /* over the panel, which it can be opened in front of */
    display: flex;
    flex-direction: column;
    min-width: 196px;
    padding: 6px;
    border: 1px solid var(--border-normal);
    border-radius: 12px;
    background: var(--bg-surface);
    box-shadow: var(--menu-shadow);
}

/* `display: flex` above would otherwise beat the browser's own
   `[hidden]` rule and leave the menu on screen permanently. */
.feedback-menu[hidden] {
    display: none;
}

.feedback-menu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: var(--text-secondary);
    font-size: 0.78rem;
    text-align: left;
    white-space: nowrap;
    cursor: pointer;
    transition: background .12s ease, color .12s ease;
}

.feedback-menu-item i {
    color: var(--text-muted);
}

.feedback-menu-item:hover {
    background: var(--surface-2);
    color: var(--text-primary);
}

.feedback-menu-danger:hover {
    background: rgba(var(--color-red-rgb), 0.14);
}

.feedback-menu-danger:hover,
.feedback-menu-danger:hover i {
    color: rgb(var(--color-red-rgb));
}

/* --- The panel ------------------------------------------------------ */

/* Hangs from the anchor under the trigger and grows down and to the
   right, and can never leave the screen: `left` is clamped by
   `placeSurface()` in feedback.js, and max-width/max-height stop at the
   viewport. Only the inline width/height are set from the resize grip. */
.feedback-panel {
    position: absolute;
    /* Overwritten by `placeSurface()` the moment the panel opens; this is the
       unclamped position, the trigger's centre a tail-inset in from the left
       edge. */
    top: 0;
    left: calc(var(--feedback-tail-x) * -1);
    width: 430px;
    height: auto;
    /* Backstops only. The real floors are what the form needs — the category
       row on one line, and an empty message field that does not scroll — and
       `minPanelWidth()` / `minPanelHeight()` in feedback.js measure both. The
       contents are template data, so a number written here goes stale the
       moment a label or a line of help text changes. */
    min-width: 320px;
    min-height: 320px;
    max-width: calc(100vw - (2 * var(--feedback-panel-inset)));
    /* The anchor is what the panel hangs from, so the floor is the bottom of
       the viewport measured from there. */
    max-height: calc(100vh - var(--feedback-anchor-y) - var(--feedback-panel-inset));
    display: flex;
    flex-direction: column;
    overflow: hidden;
    /* The right side is a gutter short, and the body puts it back as its own
       padding: the body scrolls, so it clips on x, and Send sits flush
       against that edge. The gutter is what its shadow spills into.
       Content lands in the same place either way. */
    padding: var(--feedback-pad) calc(var(--feedback-pad) - var(--feedback-body-gutter))
             var(--feedback-pad) var(--feedback-pad);
    border: 1px solid var(--border-normal);
    border-radius: 16px;
    background: var(--bg-surface);
    box-shadow: var(--menu-shadow-lifted);
    transform-origin: top left;
    opacity: 0;
    transform: translateY(-8px) scale(.97);
    transition: opacity .18s ease, transform .18s ease,
                box-shadow .15s ease, border-color .15s ease;
}

/* While the user is typing in the panel it is the thing they are working in,
   not a popup resting over the page: the edge takes the accent and a soft ring
   sits outside it, so the panel is legible against whatever it is covering. */
.feedback-panel:focus-within {
    border-color: rgba(var(--color-blue-rgb), 0.4);
    box-shadow:
        var(--menu-shadow-lifted),
        0 0 0 1px rgba(var(--color-blue-rgb), 0.16);
}

html.feedback-open .feedback-panel {
    opacity: 1;
    transform: translateY(0) scale(1);
}

/* The panel's tail, drawn on the overlay rather than on the panel: the
   panel clips its own overflow, and this has to stand outside its top
   edge. The overlay's origin IS the trigger's centre, and the panel is
   only ever placed with that centre inside its own width, so a tail
   sitting on the origin always points at the icon and always meets the
   panel. A square turned 45°: the two bordered edges
   fall outside the panel, the two bare ones merge into its surface. */
.feedback-widget::after {
    content: "";
    position: absolute;
    top: -6px;
    left: -6px;
    width: 12px;
    height: 12px;
    border-left: 1px solid var(--border-normal);
    border-top: 1px solid var(--border-normal);
    border-top-left-radius: 3px;
    background: var(--bg-surface);
    transform: rotate(45deg);
    opacity: 0;
    pointer-events: none;
    transition: opacity .18s ease, border-color .15s ease;
}

html.feedback-open .feedback-widget::after {
    opacity: 1;
}

/* Follows the panel's own focus edge, since the two are one surface. */
.feedback-widget:focus-within::after {
    border-color: rgba(var(--color-blue-rgb), 0.4);
}

.feedback-panel.feedback-dropping {
    border-color: rgba(var(--color-blue-rgb), 0.6);
}

.feedback-panel-title {
    margin: 0 0 14px;
    padding-right: 40px; /* clears the minimize control */
    font-size: 0.9rem;
    font-weight: var(--font-weight-heading);
    letter-spacing: var(--heading-tracking);
    color: var(--text-primary);
}

/* Drag grip. Only the bottom-right corner can grow a panel pinned by its
   top-left to the trigger, so there is exactly one handle and no
   ambiguity about which edge moves. */
.feedback-resize {
    position: absolute;
    bottom: 0;
    right: 0;
    width: 20px;
    height: 20px;
    cursor: nwse-resize;
    touch-action: none;
}

.feedback-resize::before {
    content: "";
    position: absolute;
    bottom: 7px;
    right: 7px;
    width: 8px;
    height: 8px;
    border-bottom: 2px solid var(--border-emphasis);
    border-right: 2px solid var(--border-emphasis);
    border-radius: 0 0 2px 0;
    transition: border-color .12s ease;
}

.feedback-resize:hover::before {
    border-color: var(--text-tertiary);
}

/* No easing mid-drag: the panel has to track the pointer exactly. */
.feedback-panel.feedback-resizing {
    transition: none;
    user-select: none;
}

.feedback-panel-controls {
    position: absolute;
    top: 11px;
    right: 11px;
    display: flex;
    gap: 2px;
}

.feedback-control {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: var(--text-muted);
    font-size: 0.8rem;
    cursor: pointer;
    transition: background .12s ease, color .12s ease;
}

.feedback-control:hover {
    background: var(--surface-2);
    color: var(--text-primary);
}

/* The body takes the slack, and the form passes it to the textarea, so
   dragging the panel taller buys writing room rather than empty space. */
.feedback-panel-body {
    flex: 1;
    min-height: 0;
    padding-right: var(--feedback-body-gutter);
    overflow-y: auto;
    overflow-x: hidden;
}

.feedback-form {
    display: flex;
    flex-direction: column;
    min-height: 100%;
}

/* --- Category segments ----------------------------------------------
   The audio widget's source tabs (tts/audio_source.css `.audio-tabs`),
   built from radios instead of buttons: same track, same chips, same
   selected wash, so choosing a category behaves like choosing between
   text-to-speech and an upload.
   -------------------------------------------------------------------- */

.feedback-segments {
    display: flex;
    margin: 0 0 16px;
    padding: 3px;
    border: 1px solid var(--border-subtle);
    border-radius: 9px;
    background: var(--surface-2);
    isolation: isolate;
}

.feedback-segment-input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.feedback-segment {
    display: inline-flex;
    /* Grow from the label's own width, never from zero. Equal-width chips
       give "Question" the same box as "Bug", which eats its padding and
       makes the row look mis-set; growing from content adds the same
       number of spare pixels to each, so the padding reads as equal. */
    flex: 1 1 auto;
    align-items: center;
    justify-content: center;
    margin: 0 !important;
    padding: 0.28rem 0.45rem;
    border: 1px solid transparent;
    border-radius: 7px;
    background: transparent;
    /* !important throughout: these are <label> elements, and forms.css
       sets label color, font-size and margin !important for real field
       labels. A tab is not a field label. */
    color: var(--text-tertiary) !important;
    /* A notch under the audio widget's 0.85rem: four chips share the width
       two source tabs have there, inside a 430px panel. */
    font-size: 0.8rem !important;
    white-space: nowrap;
    cursor: pointer;
    transition: color 0.18s ease, background-color 0.18s ease;
}

/* The glyph carries its own line box, which sits low against the label's
   text; centring it on the chip's optical middle means ignoring that box. */
.feedback-segment i {
    line-height: 1;
    font-size: 0.9em;
}

.feedback-segment-label {
    overflow: hidden;
    margin-left: 0.3rem;
    text-overflow: ellipsis;
}

.feedback-segment:hover {
    color: var(--text-secondary) !important;
}

.feedback-segment-input:checked + .feedback-segment {
    color: var(--color-blue-hover) !important;
    background: var(--feedback-accent-fill);
    border-color: transparent;
    box-shadow: var(--feedback-accent-shadow);
}

.feedback-segment-input:focus-visible + .feedback-segment {
    outline: 2px solid rgb(var(--color-blue-rgb));
    outline-offset: 1px;
}

/* --- Message ---------------------------------------------------------
   Deliberately unboxed: the panel already frames it, and a second border
   inside a bordered card is the thing that made this feel cluttered.
   -------------------------------------------------------------------- */

.feedback-textarea {
    display: block;
    flex: 1;
    width: 100%;
    /* Drives the panel's default height, which is `auto`, and its measured
       floor: the writing area is the only part that can be given more room. */
    min-height: 150px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--text-primary);
    font-size: 0.875rem;
    line-height: 1.55;
    resize: none;
}

.feedback-textarea::placeholder {
    color: var(--text-muted);
}

.feedback-textarea:focus {
    outline: 0;
}

/* --- Attachments ----------------------------------------------------- */

/* Beats `input[type="file"] { display: flex }` in forms.css, which is
   more specific than a bare class and would otherwise render the native
   control — the button and the drop zone are the interface here. */
.feedback-form input[type="file"].feedback-file-input {
    display: none;
}

.feedback-thumbs {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 12px 0 0;
    padding: 0;
    list-style: none;
}

.feedback-thumbs:empty {
    margin: 0;
}

.feedback-thumb {
    position: relative;
    width: 54px;
    height: 54px;
    border: 1px solid var(--border-subtle);
    border-radius: 9px;
    overflow: hidden;
    background: var(--bg-inset);
}

.feedback-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.feedback-thumb-file {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    color: var(--text-tertiary);
    font-size: 0.62rem;
    font-weight: var(--font-weight-strong);
}

.feedback-thumb-remove {
    position: absolute;
    top: 3px;
    right: 3px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 17px;
    height: 17px;
    border: 0;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.7);
    color: #fff;
    font-size: 0.55rem;
    cursor: pointer;
}

.feedback-thumb-remove:hover {
    background: rgb(var(--color-red-fill-rgb));
}

/* --- Action row ------------------------------------------------------ */

.feedback-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--border-subtle);
}

.feedback-tool {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: var(--text-tertiary);
    font-size: 0.82rem;
    cursor: pointer;
    transition: background .12s ease, color .12s ease;
}

.feedback-tool:hover {
    background: var(--surface-2);
    color: var(--text-primary);
}

.feedback-tool:focus-visible {
    outline: 2px solid rgb(var(--color-blue-rgb));
    outline-offset: 1px;
}

.feedback-submit {
    margin-left: auto;
    height: 32px;
    padding: 0 18px;
    border: 0;
    border-radius: 8px;
    background: var(--feedback-accent-fill);
    color: var(--color-blue-hover);
    font-size: 0.8rem;
    font-weight: var(--font-weight-control);
    box-shadow: var(--feedback-accent-shadow);
    cursor: pointer;
    transition: filter .12s ease;
}

.feedback-submit:hover {
    filter: brightness(1.08);
}

.feedback-submit:disabled {
    opacity: .6;
    cursor: default;
}

.feedback-note {
    margin: 10px 0 0;
    color: var(--text-muted);
    font-size: 0.68rem;
    line-height: 1.45;
}

.feedback-discard:hover {
    background: rgba(var(--color-red-rgb), 0.14);
    color: rgb(var(--color-red-rgb));
}

.feedback-error {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 0 0 12px;
    padding: 9px 11px;
    border-radius: 9px;
    background: rgba(var(--color-red-rgb), 0.14);
    color: var(--text-primary);
    font-size: 0.76rem;
    line-height: 1.45;
}

.feedback-error i {
    margin-top: 2px;
    color: rgb(var(--color-red-rgb));
}

/* --- Confirmation ---------------------------------------------------- */

.feedback-result {
    padding: 14px 4px 6px;
    text-align: center;
}

.feedback-result-mark {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    margin: 0 auto 12px;
    border-radius: 50%;
    background: rgba(var(--color-green-rgb), 0.16);
    color: rgb(var(--color-green-rgb));
}

.feedback-result-title {
    margin: 0 0 4px;
    color: var(--text-primary);
    font-size: 0.92rem;
    font-weight: var(--font-weight-strong);
}

.feedback-result-body {
    margin: 0 auto;
    max-width: 260px;
    color: var(--text-tertiary);
    font-size: 0.76rem;
    line-height: 1.5;
}

.feedback-result-again {
    margin-top: 14px;
    padding: 0;
    border: 0;
    background: transparent;
    color: rgb(var(--color-blue-rgb));
    font-size: 0.76rem;
    cursor: pointer;
}

.feedback-result-again:hover {
    text-decoration: underline;
}

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

@media (max-width: 575.98px) {
    .feedback-widget {
        --feedback-panel-inset: 12px;
    }
}

/* Motion is decorative here; a reduced-motion user still gets the
   opacity change so the panel's arrival is not silent. The tail is a
   `::after`, so the blanket `transform: none` cannot flatten it. */
@media (prefers-reduced-motion: reduce) {
    .feedback-panel {
        transition: opacity .15s ease;
        transform: none !important; /* beats the scale/translate rest states above */
    }
}
