/*
 * The slide-out panels: the chat on the right, the post feed on the left.
 *
 * Everything here is written once and applied to both, which is the point — this file exists because
 * adding the feed beside the chat would otherwise have meant a second copy of ~250 lines of panel,
 * divider, header, tablist and footer differing only in which edge they cling to.
 *
 * The edge is a `data-side` attribute rather than a separate class per panel, so the handful of rules
 * that genuinely differ (the transform direction, which border, which way the divider sits) are
 * stated as the two cases of one rule instead of two independent blocks that can drift.
 *
 * Loaded after assets/style.css, whose custom properties (--panel-border, --sidebar-bg, --primary…)
 * it uses throughout. Anything chat-*specific* — the message rows, the rising-icon puffs, the toasts
 * — is still in style.css; this is the shell, not the contents.
 */

:root {
    /* Each panel's docked width, dragged by the visitor and persisted per panel by sidebar.js. */
    --chat-width: 380px;
    --feed-width: 380px;

    /* The chat popout's own size. Separate from --chat-width because that one is the docked sidebar's
       drag-resized width, while the popout hides its divider — so sharing the token made the floating
       panel inherit a width nothing in that style could adjust. */
    --chat-popout-width: 440px;
    --chat-popout-height: 640px;
}

/* --- Per-panel wiring ----------------------------------------------------
 *
 * The only place a panel is named. Each one maps its own width token onto the generic --side-width
 * the rules below read, and claims a body class for the page's docking padding. Everything after this
 * block is written for "a panel" rather than for the chat or the feed. */

#chat-sidebar { --side-width: var(--chat-width); }
#feed-sidebar { --side-width: var(--feed-width); }

/* Docking pushes the page rather than covering it, which is the whole point of a panel over a popup:
   the links stay readable with chat open. It is only a padding change because <body> already centres
   .page-container, so the content slides away on its own.

   Below 1000px there is no room to give away, so the panels go back to being overlays and the padding
   is simply never applied. Both panels can be open at once, and each pushes its own edge. */
@media (min-width: 1000px) {
    body.side-open-chat {
        padding-right: calc(var(--chat-width) + 16px);
    }

    body.side-open-feed {
        padding-left: calc(var(--feed-width) + 16px);
    }
}

/* A toggle stands down while its own panel is docked: the panel's × does the closing, so the button
   does not follow it around the screen. Keyed to the matching panel, so opening the chat does not
   hide the feed's button. */
body.side-open-chat #chat-toggle,
body.side-open-feed #feed-toggle {
    opacity: 0;
    transform: scale(0.8);
    pointer-events: none;
}

/* --- The toggle --------------------------------------------------------- */

.side-toggle {
    position: fixed;
    bottom: 18px;
    z-index: 1101;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    padding: 0;
    border: 1px solid var(--panel-border);
    border-radius: 50%;
    background: linear-gradient(135deg, var(--primary), var(--secondary));
    color: #fff;
    cursor: pointer;
    box-shadow: 0 10px 28px var(--primary-glow);
    transition: transform 0.25s ease, box-shadow 0.25s ease, opacity 0.25s ease;
}

.side-toggle[data-side="right"] { right: 18px; }
.side-toggle[data-side="left"] { left: 18px; }

.side-toggle:hover {
    transform: translateY(-2px) scale(1.06);
    box-shadow: 0 14px 34px var(--primary-glow);
}

.side-toggle.active {
    transform: scale(0.94);
}

.side-toggle svg {
    flex-shrink: 0;
}

/* Unread glow. Set while something has arrived that the visitor has not seen, and cleared when the
   panel is opened, so it is a notification rather than permanent decoration. */
.side-toggle.has-activity {
    animation: sideTogglePing 1.8s ease-in-out infinite;
}

@keyframes sideTogglePing {
    0%, 100% {
        box-shadow: 0 10px 28px var(--primary-glow);
    }
    50% {
        box-shadow:
            0 10px 28px var(--primary-glow),
            0 0 0 9px rgba(157, 78, 221, 0.12),
            0 0 28px 7px rgba(0, 242, 254, 0.45);
    }
}

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

.side-panel {
    position: fixed;
    top: 0;
    bottom: 0;
    z-index: 1100;
    display: flex;
    flex-direction: column;
    width: var(--side-width, 380px);
    max-width: 100vw;
    /* Darker than the page but not opaque, so the wallpaper still reads through it. The blur is what
       keeps the contents legible over a busy backdrop; without it the text fights the image. */
    background: var(--sidebar-bg);
    backdrop-filter: blur(18px) saturate(1.1);
    /* visibility, not display: the panes keep their size so a reopened iframe does not relayout, and
       a closed panel is still out of the tab order. */
    visibility: hidden;
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), visibility 0.3s;
}

/* The two edges. Each slides out the way it came in, and shadows inward. */
.side-panel[data-side="right"] {
    right: 0;
    border-left: 1px solid var(--panel-border);
    box-shadow: -18px 0 48px rgba(0, 0, 0, 0.38);
    transform: translateX(100%);
}

.side-panel[data-side="left"] {
    left: 0;
    border-right: 1px solid var(--panel-border);
    box-shadow: 18px 0 48px rgba(0, 0, 0, 0.38);
    transform: translateX(-100%);
}

.side-panel.open {
    transform: translateX(0);
    visibility: visible;
}

/* --- chat-style: popout -------------------------------------------------
 *
 * The chat panel floating above its toggle instead of docked to the edge. It never takes room from
 * the page, so the docking padding is cancelled and the divider has nothing to divide.
 *
 * Only the chat has this: it is one of the chat styles in chat/config.json, not something a panel can
 * be in general. The feed is always docked. */
body[data-chat-style="popout"].side-open-chat {
    padding-right: 16px;
}

[data-chat-style="popout"] #chat-sidebar {
    top: auto;
    right: 18px;
    bottom: 86px;
    width: min(var(--chat-popout-width), calc(100vw - 36px));
    height: min(var(--chat-popout-height), calc(100vh - 130px));
    border: 1px solid var(--panel-border);
    border-radius: 18px;
    overflow: hidden;
    opacity: 0;
    transform: translateY(16px) scale(0.97);
    transition: opacity 0.26s ease, transform 0.26s ease, visibility 0.26s;
}

[data-chat-style="popout"] #chat-sidebar.open {
    opacity: 1;
    transform: translateY(0) scale(1);
}

/* The toggle is the popout's anchor, so it stays put and visible rather than standing down. */
[data-chat-style="popout"] #chat-resizer {
    display: none;
}

body[data-chat-style="popout"].side-open-chat #chat-toggle {
    opacity: 1;
    transform: scale(0.94);
    pointer-events: auto;
}

@media (max-width: 520px) {
    [data-chat-style="popout"] #chat-sidebar {
        right: 10px;
        left: 10px;
        width: auto;
        bottom: 78px;
        height: min(72vh, 540px);
    }
}

/* --- The divider -------------------------------------------------------- */

/* Draggable to resize. Wider than it looks: the visible line is 2px but the grab area is 10px,
   because a 1px target is a test of patience. */
.side-resizer {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 10px;
    cursor: col-resize;
    touch-action: none;
    z-index: 2;
}

/* On the page's side of the panel, whichever side that is. */
.side-panel[data-side="right"] .side-resizer { left: -5px; }
.side-panel[data-side="left"] .side-resizer { right: -5px; }

.side-resizer::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 4px;
    width: 2px;
    background: var(--primary);
    opacity: 0;
    transition: opacity 0.18s ease;
}

.side-resizer:hover::after,
.side-resizer:focus-visible::after,
body.side-resizing .side-resizer::after {
    opacity: 0.85;
}

.side-resizer:focus-visible {
    outline: none;
}

/* While dragging, nothing else should take the pointer — an iframe in a pane would otherwise swallow
   the pointermove the moment the cursor crossed into it. */
body.side-resizing {
    cursor: col-resize;
    user-select: none;
}

body.side-resizing iframe {
    pointer-events: none;
}

/* The width is being driven by the drag, so it must not lag behind it. */
body.side-resizing,
body.side-resizing .side-panel {
    transition: none;
}

/* Resizing is a pointer affordance; below the docking breakpoint a panel is a full-screen overlay
   and there is nothing to resize. Must agree with DOCK_BREAKPOINT in assets/sidebar.js. */
@media (max-width: 999px) {
    .side-resizer {
        display: none;
    }
}

/* --- The header --------------------------------------------------------- */

.side-panel-header {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    padding: 8px 10px;
    border-bottom: 1px solid var(--panel-border);
}

/* The panel's accessible name, and nothing else: the tabs took its place visually. Clipped rather
   than `display: none`, which would take it out of the accessibility tree and leave the <aside>'s
   aria-labelledby pointing at nothing. */
.side-title {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

.side-close {
    flex: 0 0 auto;
    width: 30px;
    height: 30px;
    border: none;
    border-radius: 9px;
    background: transparent;
    color: var(--text-muted);
    font-size: 1.4rem;
    line-height: 1;
    cursor: pointer;
}

.side-close:hover {
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-main);
}

/* --- Tabs --------------------------------------------------------------- */

/* In the header, so it gives up its own padding and divider to the row it sits in. `min-width: 0` is
   what lets it actually scroll: a flex item defaults to min-width:auto and would otherwise refuse to
   shrink below its content, pushing the close button off the panel. */
.side-tabs {
    display: flex;
    gap: 4px;
    flex: 1;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
}

.side-tabs::-webkit-scrollbar {
    display: none;
}

.side-tab {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    padding: 7px 9px;
    border: 1px solid transparent;
    border-radius: 10px;
    background: transparent;
    color: var(--text-muted);
    font-family: var(--font-body);
    font-size: 0.75rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}

.side-tab:hover {
    background: rgba(157, 78, 221, 0.12);
    color: var(--text-main);
}

.side-tab[aria-selected="true"] {
    background: rgba(157, 78, 221, 0.18);
    border-color: var(--card-hover-border);
    color: var(--text-main);
}

/*
 * The tab bar under "prefer platform colours" — see the block at the top of assets/style.css.
 *
 * Only the icon takes the colour, not the label: the selected tab is the only one with its name
 * showing, and that name is body text doing the work the tint cannot. The readable ink rather than
 * the flat brand colour, because these sit on the sidebar's own translucent panel at 16px.
 */
[data-platform-colors] .side-tab[data-provider] .side-tab-icon {
    color: var(--platform-ink);
}

[data-platform-colors] .side-tab[data-provider][aria-selected="true"] {
    background: color-mix(in srgb, var(--provider, var(--primary)) 16%, transparent);
    border-color: color-mix(in srgb, var(--provider, var(--primary)) 45%, transparent);
}

[data-platform-colors] .side-tab[data-provider]:hover {
    background: color-mix(in srgb, var(--provider, var(--primary)) 12%, transparent);
}

.side-tab-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.side-tab-icon svg {
    width: 16px;
    height: 16px;
}

/* Six tabs do not fit a 380px rail with their names on, so only the open one is labelled. The name is
   still in the accessible tree either way, and the strip scrolls if it ever does overflow. */
.side-tab-label {
    display: none;
    white-space: nowrap;
}

.side-tab[aria-selected="true"] .side-tab-label {
    display: inline;
}

/* --- Panes -------------------------------------------------------------- */

.side-panes {
    flex: 1;
    min-height: 0;
    position: relative;
}

.side-pane {
    position: absolute;
    inset: 0;
}

.side-pane[hidden] {
    display: none;
}

/* A line of muted, centred text in a panel: "nothing yet", "unavailable", a loading note.

   Its twin, `.chat-status`, stays in assets/style.css rather than being merged into this rule. They
   look identical and they are not the same thing: this one belongs to the panel shell, and that one
   is the chat's own — used by the standalone page at /chat/, which has no sidebar and so does not
   load this file. Merging them here silently stripped that page's status line of its size, colour and
   its `:empty` rule, because the selector it needed had moved into a stylesheet it never loads. */
.side-status {
    padding: 14px;
    margin: 0;
    font-size: 0.8rem;
    color: var(--text-muted);
    text-align: center;
}

.side-status:empty {
    display: none;
}

/* --- The footer --------------------------------------------------------- */

.side-footer {
    padding: 9px 14px;
    border-top: 1px solid var(--panel-border);
    font-size: 0.72rem;
    color: var(--text-muted);
    text-align: center;
}

.side-footer a {
    color: var(--secondary);
    text-decoration: none;
}

.side-footer a:hover {
    text-decoration: underline;
}

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

/* Under 1000px a panel covers the page instead of pushing it, and its toggle would sit underneath,
   so it steps out of the way; the header's × is how a panel is dismissed there. */
@media (max-width: 999px) {
    .side-panel {
        width: min(var(--side-width, 380px), 100vw);
    }

    body.side-open-chat #chat-toggle,
    body.side-open-feed #feed-toggle {
        opacity: 0;
        pointer-events: none;
    }
}

@media (max-width: 520px) {
    .side-toggle {
        bottom: 12px;
        width: 46px;
        height: 46px;
    }

    .side-toggle[data-side="right"] { right: 12px; }
    .side-toggle[data-side="left"] { left: 12px; }
}

/* --- Reduced motion ---------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    /* The unread state still has to be visible, so the pulsing glow becomes a steady one — the
       global animation rule in style.css would otherwise freeze it on whichever keyframe it
       happened to start at. */
    .side-toggle.has-activity {
        animation: none;
        box-shadow:
            0 10px 28px var(--primary-glow),
            0 0 0 7px rgba(157, 78, 221, 0.14),
            0 0 24px 6px rgba(0, 242, 254, 0.4);
    }
}
