/* jelly-ui: the structural half of the sidebar -- the two drag handles, the
   fold arrow, the rename input, the drop previews, the rule under a section
   title, and the open/close toggle and its slide (at the foot of this file).

   What is deliberately NOT here: how a sidebar row looks. A jellytodo board row
   and a jellystat domain row have nothing in common beyond being a row, so
   .sidebar_item, .active_sidebar_item, the column's width and its background
   all stay in the app -- same split drag.css already draws (see jelly-ui/README).

   What the app does hand this file, it hands over as custom properties, because
   each is a per-app value rather than a constant:

       --jelly-sidebar-accent   the drop preview's colour (jellystat: the
                                domain's own accent_color; jellytodo: a fixed
                                blue). Falls back to a blue so a consumer that
                                sets nothing still gets a visible preview.

   plus three the open/close toggle takes -- --jelly-sidebar-width and the two
   optional ones, all described in that section.

   Everything else is currentColor, which is what makes these rows survive the
   dark-mode flip: both apps previously hardcoded #000000 on the title text and
   its divider rule, which is invisible on a black sidebar (jellytodo#40). */

/* Positioning context for the section drop indicator, which is absolutely
   positioned at a boundary between two sections rather than inserted into the
   row flow. The class is on the container in the app's markup, which is also
   what JellySidebar.register() is pointed at. */
.sidebar_list {
    position: relative;
}

/* THE ROW HANDLE -- three stacked bars, revealed on hover. A row is
   draggable='false' until this is pressed, so the row's own link keeps
   working; see the mousedown handler in sidebar.js.

   Named distinctly from any app's own .drag_handle: jellytodo's ticket and
   lane handles are a single always-visible glyph gated by permission, and
   sharing the class name once made them inherit this opacity: 0 and never
   reappear (jellytodo#41). */
.sidebar_drag_handle {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 3px;

    margin-right: 8px;

    cursor: grab;
    opacity: 0;
}

.sidebar_item:hover .sidebar_drag_handle {
    opacity: 1;
}

.sidebar_drag_handle span {
    display: block;
    width: 14px;
    height: 2px;
    background-color: gray;
}

/* The row drag's preview: a line on the edge the row would land against.
   Transparent borders reserved on both edges at all times, so a row does not
   change height the moment one of them is coloured in. */
.sidebar_draggable {
    box-sizing: border-box;
    border-top: 2px solid transparent;
    border-bottom: 2px solid transparent;
}

.sidebar_draggable.drag_over_top {
    border-top-color: var(--jelly-sidebar-accent, #3b82f6);
}

.sidebar_draggable.drag_over_bottom {
    border-bottom-color: var(--jelly-sidebar-accent, #3b82f6);
}

/* SECTION TITLES. The rule under the title is what makes the row read as a
   header over the rows below it rather than another row; it starts a quarter
   of the way across so it separates without spanning the whole column. */
.sidebar_title_item {
    cursor: default;
    position: relative;
}

.sidebar_title_item::after {
    content: '';
    position: absolute;
    left: calc(25% - 4.5px);
    right: 18px;
    bottom: 6px;
    height: 1px;
    background-color: currentColor;
}

/* the divider sits exactly where the rename input's own bottom border goes, so
   it reads as a stray line inside the box while the title is being edited */
.sidebar_title_item.sidebar_title_editing::after {
    display: none;
}

.sidebar_title_text {
    font-size: 9pt;
    font-weight: bold;
    color: inherit;
    text-transform: uppercase;
    cursor: text;
}

/* The input a title's text is swapped for while it is being edited
   (jellytodo#48) -- matched to .sidebar_title_text so the row doesn't jump
   when it appears, and right-aligned like the rest of the column. */
.sidebar_title_input {
    flex: 1;
    min-width: 0px;

    font-family: inherit;
    font-size: 9pt;
    font-weight: bold;
    text-transform: uppercase;
    text-align: right;
}

/* THE SECTION GRIP (jellytodo#55) -- drags the title plus every row under it,
   where the three-bar handle beside the text still drags the title row on its
   own. Absolutely positioned rather than a flex child so it lines up with the
   left end of the divider rule above, which is what marks out how wide a
   section header reads as; a flex child would sit wherever the right-aligned
   title text happened to end. Six dots rather than three more bars, so the two
   handles on the row don't read as the same control. */
.sidebar_section_handle {
    position: absolute;
    left: calc(25% - 4.5px);
    top: 50%;
    transform: translateY(-50%);

    font-size: 11pt;
    line-height: 1;
    color: gray;

    cursor: grab;
    opacity: 0;
    user-select: none;
}

.sidebar_item:hover .sidebar_section_handle {
    opacity: 1;
}

.sidebar_section_handle:active {
    cursor: grabbing;
}

/* the rename input fills the row, so the grip would sit on top of the text
   being typed */
.sidebar_title_item.sidebar_title_editing .sidebar_section_handle {
    display: none;
}

/* The section drag's preview: an absolutely positioned bar snapped to the
   boundary the block would land at. Never a real child of the row flow -- an
   in-flow indicator would push the whole list down by its own height each time
   it appeared or moved. */
.sidebar_drop_indicator {
    position: absolute;
    left: 0px;
    width: 100%;
    height: 4px;

    pointer-events: none;
    border-radius: 2px;
    background-color: var(--jelly-sidebar-accent, #3b82f6);
}

/* THE FOLD (jellytodo#50). The arrow points down when the rows under the title
   are showing and left when they are folded away. Fixed width and centred so
   swapping the two glyphs -- which aren't the same width -- doesn't nudge the
   title text sideways. */
.sidebar_title_arrow {
    width: 12px;
    margin-left: 6px;

    font-size: 8pt;
    line-height: 1;
    text-align: center;
    color: currentColor;

    cursor: pointer;
    user-select: none;
}

/* A row folded away under a collapsed title. Not rendered at all rather than
   dimmed or shrunk: the point of folding a section is to get the rows under it
   out of a long column.

   The class is written twice on purpose. Both consumers load their own
   stylesheet after this one and both set `display: flex` on .sidebar_item to
   lay a row out -- equal specificity, so the app's rule wins on order and a
   folded row stayed on screen in both apps (jellystat#31). Doubling the class
   settles it on specificity instead, which no ordering can undo. Any rule in
   this file that has to beat an app's own needs the same treatment; see
   jelly-style.md. */
.sidebar_item_hidden.sidebar_item_hidden {
    display: none;
}

/* THE STATUS DOT (jellytodo#80, shared in jellystat#31). A filled circle at the
   right-hand end of a row, saying that something about that row's item is true
   right now -- in jellytodo, that one of the board's watched lanes is holding
   tickets.

   The app renders the <span> in every row and leaves it there; lighting one is
   a class toggle and nothing else, so a poll running every few seconds writes
   to the DOM only when an answer actually changed.

   Not drawn at all while unlit, rather than laid out and transparent: an unlit
   row then keeps exactly the right-hand margin every other row in the column
   has, and only a row with something to say is any wider.

   Three custom properties, all optional:

       --jelly-sidebar-dot-size    the diameter (default 13pt -- jellytodo's
                                   .action_icon size, so its sidebar dot stands
                                   as tall as the same dot in a lane header)
       --jelly-sidebar-dot-color   the fill (default: a green)
       --jelly-sidebar-dot-border  the ring (default: currentColor, so it
                                   survives an app's dark-mode flip untouched)

   What lights it is entirely the app's business: there is no poll and no URL in
   here, same as the rest of this module. The app decides and calls
   JellySidebar.setItemDot/setItemDots. */
.sidebar_status_dot {
    box-sizing: border-box;

    width: var(--jelly-sidebar-dot-size, 13pt);
    height: var(--jelly-sidebar-dot-size, 13pt);
    flex-shrink: 0;
    margin-left: 8px;

    border: 2.5px solid var(--jelly-sidebar-dot-border, currentColor);
    border-radius: 50%;
    background-color: var(--jelly-sidebar-dot-color, rgb(34, 160, 70));

    display: none;
}

/* Doubled like .sidebar_item_hidden above, and for the same reason: this has to
   beat both the rule directly above it and any `display` an app's later-loading
   stylesheet puts on a row's children. */
.sidebar_status_dot_lit.sidebar_status_dot_lit {
    display: block;
}

/* OPEN/CLOSE (jellytodo#54, shared in jellystat#31) -- clicking #sidebar_toggle
   puts .sidebar_hidden on <body>; everything from there is these rules. The
   content pane keeps its right edge where it is and takes a negative left
   margin of exactly the sidebar's width, so it grows leftwards across the
   stationary sidebar over 300ms and ends up covering the window. The sidebar
   itself never moves.

   This is the one animation in either app (jelly-style.md's "no animation
   beyond instant class toggles"). The movement is the feature: it is what says
   the sidebar went behind the content pane rather than being deleted.

   Three things an app supplies:

       #sidebar_toggle          the circle, anywhere in the document -- it is
                                position: fixed, so where it sits in the markup
                                doesn't matter (JellySidebar.setupToggle wires
                                the click)
       .jelly_sidebar_pane      on the element that slides, i.e. the content
                                column next to #sidebar. Its open-state margin,
                                left padding and left corner radii have to be
                                declared at class specificity too -- both apps
                                had them on `#viewer`/`#domain_viewer`, which
                                outranks the `body.sidebar_hidden
                                .jelly_sidebar_pane` rule below, and the pane
                                then simply never moves. Nothing else about the
                                pane has to give up its id.
       --jelly-sidebar-width    how far it slides. Must be the sidebar's real
                                width -- read it from the same declaration that
                                sizes the column rather than restating the
                                number, or the two drift and a sliver of
                                sidebar stays visible.

   Two it may supply:

       --jelly-sidebar-toggle-color   the circle (default: currentColor)
       --jelly-sidebar-closed-padding the pane's left padding while closed,
                                      which has to clear the circle now that
                                      the pane's own first heading starts where
                                      the circle sits (default: 52px)

   Not here, because they are per-app looks rather than mechanism: the pane's
   colours, its corner radii, and what happens at the mobile breakpoint -- both
   apps collapse the sidebar into a top navbar at a width of their own choosing,
   where there is no column to slide out from under and the toggle goes away. */
.jelly_sidebar_pane {
    /* above the sidebar, so closing slides this pane *over* it rather than
       pushing it out of frame */
    position: relative;
    z-index: 1;

    transition: margin-left 300ms ease, border-radius 300ms ease, padding-left 300ms ease;
}

body.sidebar_hidden .jelly_sidebar_pane {
    margin-left: calc(-1 * var(--jelly-sidebar-width));

    /* rounded left corners only read as "pane offset from the sidebar to its
       left", so they square off as the pane reaches the window edge */
    border-top-left-radius: 0px;
    border-bottom-left-radius: 0px;

    padding-left: var(--jelly-sidebar-closed-padding, 52px);
}

/* The delayed visibility flip takes the covered sidebar out of tab order and
   out of screen readers without cutting the closing slide short: 0s transition
   with a 300ms delay flips it at the end of the slide, and the rule above --
   which has no delay -- flips it back instantly on open. */
#sidebar {
    visibility: visible;
}

body.sidebar_hidden #sidebar {
    visibility: hidden;
    transition: visibility 0s linear 300ms;
}

/* Stays in the window's top left corner whether the sidebar is open or closed,
   above the pane sliding underneath it. Clear fill on purpose: a plain drawn
   circle, not an icon or a glyph (jelly-style.md's "no images/icons beyond
   content"). */
#sidebar_toggle {
    position: fixed;
    top: 12px;
    left: 12px;
    z-index: 2;

    width: 24px;
    height: 24px;
    box-sizing: border-box;

    border: 4px solid var(--jelly-sidebar-toggle-color, currentColor);
    border-radius: 50%;
    background-color: transparent;

    cursor: pointer;
}
