@charset "UTF-8";

/* =========================================
   LEGACY ALIASES - do not use in new code
   Canonical tokens live in J2W/tokens.css (loaded first).
   The old divergent scales unify on the J2Web values, which shifts
   some FX components by 1-2px intentionally.
   ========================================= */
:root {
    --fx2w-color-primary: var(--j2w-accent);
    --fx2w-color-primary-hover: var(--j2w-accent-hover);
    --fx2w-color-white: var(--j2w-surface);
    --fx2w-color-white-overlay: var(--j2w-hover-tint);
    --fx2w-color-black-bg: var(--j2w-surface-sunken);
    --fx2w-color-gray: var(--j2w-border-strong);
    --fx2w-color-gray-border: var(--j2w-border);
    --fx2w-color-gray-bg: var(--j2w-surface-sunken);
    --fx2w-color-selection: var(--j2w-selection);
    --fx2w-spacing-xs: 2px;
    --fx2w-spacing-sm: var(--j2w-space-1);
    --fx2w-spacing-md: var(--j2w-space-2);
    --fx2w-spacing-em-sm: 0.166667em;
    --fx2w-spacing-em-md: 0.333333em;
    --fx2w-spacing-em-lg: 0.666667em;
    --fx2w-radius-sm: var(--j2w-radius-sm);
    --fx2w-radius-md: var(--j2w-radius-md);
    --fx2w-radius-lg: var(--j2w-radius-lg);
    --fx2w-shadow-hover: inset 0 0 0 9999px var(--j2w-hover-tint);
    --fx2w-shadow-selection: inset 0 0 0 999px var(--j2w-selection);
    --fx2w-shadow-toggle-off: inset 0 0 0 999px var(--j2w-active-tint);
    --fx2w-backdrop-blur: var(--j2w-backdrop-blur);
}

/* =========================================
   BASE LAYOUT COMPONENTS
   Intentional override: every bare div becomes a clipped stretch grid;
   FXML layout translation depends on it. The body rule lives in j2w.css.
   overflow: hidden keeps minmax(0, 1fr) tracks from blowing out.
   ========================================= */
pane,
div,
grid,
cell {
    display: grid;
    justify-content: stretch;
    align-content: stretch;
    grid-template-rows: minmax(0, 1fr);
    grid-template-columns: minmax(0, 1fr);
    overflow: hidden;
}

/* =========================================
   CONTAINER COMPONENTS
   ========================================= */
flowpane>* {
    display: inline-block;
}

/* scrollpane rules live in j2w.css (J2Web declares the tag) */
listview {
    overflow: hidden;
    display: grid;
    justify-content: stretch;
    align-content: stretch;
    grid-template-rows: minmax(0, 1fr);
    grid-template-columns: minmax(0, 1fr);
    background-color: var(--j2w-surface);
    border: 1px solid var(--j2w-border);
    border-radius: var(--j2w-radius-md);
}

listview>content {
    display: block;
    overflow-x: auto;
    overflow-y: auto;
}

/*
 * The list body, not a row. ListView's constructor puts a single Grid inside the
 * scroll content and every cell goes in there, so this selector matches that one
 * wrapper and never a row - which makes this the list's inner padding, holding the
 * rows off the border.
 *
 * The hover and selected rules that used to sit here were written as if the rows
 * were the direct children. They are not, so the hover tinted the whole list at
 * once - and the row under the pointer took the tint twice, once as itself and
 * once through the list beneath it - while the selected rules never matched
 * anything at all: updateSelection() writes 'mode' onto the cells. Both states
 * belong to the cell and are declared with it, further down.
 */
listview>content>* {
    padding: var(--j2w-space-1) var(--j2w-space-2);
}

/* =========================================
   SPLITPANE COMPONENT
   ========================================= */
splitpane {
    overflow: hidden;
    display: grid;
    justify-content: stretch;
    align-content: stretch;
}

/* An fr track floors at its item's automatic minimum, so a divider driven to 0
   would leave a sliver of the panel behind instead of reaching the edge. */
splitpane>* {
    min-width: 0;
    min-height: 0;
}

/* Only a divider moved from code slides - collapsing a side panel, restoring a
   saved layout. SplitPane sets this class there and clears it on drag, so the
   mouse never fights a transition. */
splitpane.j2w-animated {
    transition:
        grid-template-columns var(--j2w-duration-overlay) var(--j2w-ease),
        grid-template-rows var(--j2w-duration-overlay) var(--j2w-ease);
}

/* CSS-only grip: an 8px hit area with a centered pill that highlights
   on hover/drag (replaces the old PNG grip images). */
splitpane>.separator-v,
splitpane>.separator-h {
    justify-items: center;
    align-items: center;
}

splitpane>.separator-v {
    cursor: row-resize;
    min-height: 8px;
}

splitpane>.separator-h {
    cursor: col-resize;
    min-width: 8px;
}

splitpane>.separator-v::after,
splitpane>.separator-h::after {
    content: "";
    display: block;
    border-radius: var(--j2w-radius-full);
    background-color: var(--j2w-border-strong);
    transition:
        background-color var(--j2w-duration-base) var(--j2w-ease),
        scale var(--j2w-duration-base) var(--j2w-ease);
}

splitpane>.separator-v::after {
    width: 32px;
    height: 4px;
}

splitpane>.separator-h::after {
    width: 4px;
    height: 32px;
}

splitpane>.separator-v:hover::after,
splitpane>.separator-h:hover::after,
splitpane>.separator-v:active::after,
splitpane>.separator-h:active::after {
    background-color: var(--j2w-accent);
    scale: 1.2;
}

/* =========================================
   BORDERPANE COMPONENT
   ========================================= */
borderpane {
    overflow: hidden;
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr) max-content;
    grid-template-rows: max-content minmax(0, 1fr) max-content;
    grid-template-areas: "t t t" "l c r" "b b b";
    align-items: stretch;
    justify-items: stretch;
}

borderpane>div-center {
    overflow: hidden;
    display: grid;
    grid-area: c;
    align-items: stretch;
    justify-items: stretch;
}

borderpane>div-top {
    overflow: hidden;
    display: grid;
    grid-area: t;
    justify-items: stretch;
}

borderpane>div-left {
    overflow: hidden;
    display: grid;
    grid-area: l;
    align-items: stretch;
}

borderpane>div-bottom {
    overflow: hidden;
    display: grid;
    grid-area: b;
    justify-items: stretch;
}

borderpane>div-right {
    overflow: hidden;
    display: grid;
    grid-area: r;
    align-items: stretch;
}

/* =========================================
   ACCORDION COMPONENT
   ========================================= */
/* The accordion sizes its panes itself, so the motion has to live here as well as on the pane:
   AccordionPane writes 1fr for the open pane and 0fr for the rest, which interpolate. */
accordion {
    transition: grid-template-rows var(--j2w-duration-base) var(--j2w-ease);
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    justify-items: stretch;
    align-items: stretch;
    border: 1px solid var(--j2w-border);
    border-radius: var(--j2w-radius-lg);
    background-color: var(--j2w-surface);
    box-shadow: var(--j2w-shadow-1);
    overflow: hidden;
}

/* Clean separators between stacked TitledPanes inside accordion */
accordion > titledpane {
    border: none;
    border-radius: 0;
    border-bottom: 1px solid var(--j2w-border);
    box-shadow: none;
}

accordion > titledpane:last-child {
    border-bottom: none;
}

/* =========================================
   MENUBAR & TOOLBAR
   ========================================= */
menubar,
toolbar {
    background-color: var(--j2w-surface);
    border-bottom: 1px solid var(--j2w-border);
}

menubar,
toolbar {
    display: grid;
    grid-template-columns: max-content;
    grid-template-rows: max-content;
    justify-content: start;
    align-content: center;
    justify-items: start;
    align-items: center;
    grid-auto-flow: column;
    padding: var(--j2w-space-1) var(--j2w-space-2);
    gap: var(--j2w-space-1);
}

/* menubar stays unclipped so the absolutely-positioned dropdown can
   escape; toolbar clips like other bars. */
menubar {
    overflow: visible;
}

toolbar {
    overflow: hidden;
}

menubar:focus {
    box-shadow: none;
}

/* Anchor for the dropdown */
menubar>pane {
    position: relative;
    overflow: visible;
}

menubar>pane>div-label {
    cursor: pointer;
    padding: var(--j2w-space-1) var(--j2w-space-3);
    border-radius: var(--j2w-radius-sm);
    transition:
        background-color var(--j2w-duration-base) var(--j2w-ease),
        color var(--j2w-duration-base) var(--j2w-ease);
}

menubar>pane>div-label:hover {
    background-color: var(--j2w-hover-tint);
}

menubar>pane[selected]>div-label,
menubar>pane[selected]>div-label:hover {
    background-color: var(--j2w-accent-subtle);
    color: var(--j2w-accent);
}

/* Dropdown: fresh DOM on open, so an entry animation is diff-safe here */
menubar>pane>div-content {
    position: absolute;
    top: 100%;
    left: 0;
    min-width: max-content;
    display: grid;
    z-index: 1;
    margin-top: var(--j2w-space-1);
    border: 1px solid var(--j2w-border);
    border-radius: var(--j2w-radius-md);
    padding: var(--j2w-space-1);
    background-color: var(--j2w-surface-overlay);
    box-shadow: var(--j2w-shadow-3);
    transform-origin: top left;
    animation: j2w-pop-in var(--j2w-duration-fast) var(--j2w-ease-out);
}

/* Exit: MenuBar.collapseAnimated marks the dropdown, holds for the animation
   window, then unpublishes it. Without the hold the node would simply vanish. */
menubar>pane>div-content.j2w-closing {
    animation: j2w-pop-out var(--j2w-duration-fast) var(--j2w-ease) forwards;
}

menuitem {
    cursor: pointer;
    padding: var(--j2w-space-1) var(--j2w-space-3);
    border-radius: var(--j2w-radius-sm);
    transition: background-color var(--j2w-duration-fast) var(--j2w-ease);
}

menuitem:hover {
    background-color: var(--j2w-hover-tint);
}

sepmenuitem {
    border-top: 1px solid var(--j2w-border);
    margin: var(--j2w-space-1) 0;
}

toolbar>* {
    margin: 0;
}

/* =========================================
   TITLEDPANE COMPONENT
   ========================================= */
/* The body slides instead of appearing: the row track carries the motion, so the
   header stays put and the surrounding layout follows. Both states are minmax()
   so the track list interpolates. Collapsing needs the server to keep the body
   published for the length of this transition - see TitledPane.swapExpanded. */
titledpane {
    display: grid;
    grid-template-rows: max-content minmax(0, 1fr);
    transition: grid-template-rows var(--j2w-duration-base) var(--j2w-ease);
    grid-template-columns: minmax(0, 1fr);
    justify-items: stretch;
    align-items: stretch;
    border: 1px solid var(--j2w-border);
    border-radius: var(--j2w-radius-lg);
    background-color: var(--j2w-surface);
    box-shadow: var(--j2w-shadow-1);
    overflow: hidden;
}

titledpane>div-title {
    display: grid;
    grid-template-rows: max-content;
    grid-template-columns: max-content minmax(0, 1fr);
    justify-items: start;
    align-items: center;
    gap: var(--j2w-space-2);
    border-bottom: 1px solid var(--j2w-border);
    padding: var(--j2w-space-2) var(--j2w-space-3);
    background-color: var(--j2w-surface-sunken);
    font-weight: 500;
    transition: background-color var(--j2w-duration-base) var(--j2w-ease);
}

titledpane>div-title:hover {
    background-color: color-mix(in srgb, var(--j2w-text) 5%, var(--j2w-surface-sunken));
    cursor: pointer;
}

/* One chevron icon, rotated by the expanded attribute */
titledpane>div-title .j2w-icon {
    transition: transform var(--j2w-duration-overlay) var(--j2w-ease);
    opacity: 0.5;
}

titledpane>div-title:hover .j2w-icon {
    opacity: 0.8;
}

titledpane:not([expanded])>div-title .j2w-icon {
    transform: rotate(-90deg);
}

titledpane:not([expanded]) {
    grid-template-rows: max-content minmax(0, 0fr);
}

titledpane>div-content {
    overflow: hidden;
    min-height: 0;
    display: grid;
    justify-content: stretch;
    align-content: stretch;
}

/* =========================================
   TABPANE COMPONENT
   ========================================= */
tabpane {
    overflow: hidden;
    display: grid;
    grid-template-rows: max-content minmax(0, 1fr);
    grid-template-columns: minmax(0, 1fr);
}

tabpane>div-title {
    display: grid;
    grid-template-rows: max-content;
    grid-template-columns: max-content;
    grid-auto-columns: max-content;
    justify-items: start;
    grid-auto-flow: column;
    min-height: 20px;
    background: transparent;
    border-bottom: 1px solid var(--j2w-border);
    padding: 0;
    overflow: auto;
}

tabpane>div-title>* {
    display: grid;
    align-items: center;
    background: transparent;
    border-bottom: 2px solid transparent;
    margin: 0 0 -1px;
    padding: var(--j2w-space-2) var(--j2w-space-4);
    cursor: pointer;
    font-weight: 400;
    color: var(--j2w-text-secondary);
    transition:
        color var(--j2w-duration-base) var(--j2w-ease),
        border-color var(--j2w-duration-base) var(--j2w-ease),
        background-color var(--j2w-duration-base) var(--j2w-ease);
}

tabpane>div-title>*:hover {
    background-color: var(--j2w-hover-tint);
    color: var(--j2w-text);
}

tabpane>div-title>*[selected] {
    background: transparent;
    color: var(--j2w-accent);
    border-bottom-color: var(--j2w-accent);
    font-weight: 500;
    cursor: default;
}

tabpane>div-content {
    overflow: hidden;
    display: grid;
    grid-template-rows: minmax(0, 1fr);
    grid-template-columns: minmax(0, 1fr);
    justify-content: stretch;
    align-content: stretch;
}

/* The selected body is a different node than the one it replaces, so it is
   genuinely new DOM and an entry keyframe is diff-safe here. It re-plays if
   div-content itself is ever repatched; updates inside a tab body are not,
   so in practice this fires on a tab change.

   A plain fade at the fast duration was invisible in practice: it starts only once the patch lands,
   by which point the eye has already moved. The body therefore rises a few pixels as well, over the
   base duration, which is enough to read as a change of screen without feeling slow. */
tabpane>div-content>* {
    animation: j2w-enter var(--j2w-duration-base) var(--j2w-ease-out);
}

/* =========================================
   TABLEVIEW COMPONENT
   ========================================= */
tableview {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    grid-template-rows: max-content minmax(0, 1fr);
    justify-content: stretch;
    align-content: stretch;
    background-color: var(--j2w-surface);
    border: 1px solid var(--j2w-border);
    border-radius: var(--j2w-radius-md);
    overflow: hidden;
}

tableview>header,
tableview>top {
    display: grid;
    background: var(--j2w-surface-sunken);
    border-bottom: 1px solid var(--j2w-border);
}

tableview>top {
    overflow-y: scroll;
}

tableview>left {
    display: grid;
    justify-content: stretch;
    align-content: stretch;
    background: var(--j2w-surface-sunken);
    border-right: 1px solid var(--j2w-border);
    overflow-x: scroll;
}

tableview>content {
    display: grid;
    overflow-x: scroll;
    overflow-y: scroll;
    justify-content: stretch;
    align-content: stretch;
}

tableview>content>cell,
tableview>fixcontent>cell {
    border-right: 1px solid color-mix(in srgb, var(--j2w-border) 60%, transparent);
    border-bottom: 1px solid color-mix(in srgb, var(--j2w-border) 45%, transparent);
}

tableheader {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
    padding: var(--j2w-space-2) var(--j2w-space-3);
    cursor: pointer;
    justify-items: center;
    text-align: center;
    align-items: center;
    align-self: stretch;
    border-right: 1px solid var(--j2w-border);
    color: var(--j2w-text-secondary);
    font-weight: 600;
    font-size: var(--j2w-text-sm);
    letter-spacing: 0.02em;
    transition:
        background-color var(--j2w-duration-base) var(--j2w-ease),
        color var(--j2w-duration-base) var(--j2w-ease);
}

tableheader:hover {
    background-color: color-mix(in srgb, var(--j2w-text) 5%, var(--j2w-surface-sunken));
    color: var(--j2w-text);
}

/* Sort direction affordance; the sort attribute is set by TableView */
tableheader[sort]::after {
    font-size: 0.6em;
    opacity: 0.7;
    margin-left: var(--j2w-space-1);
}

tableheader[sort="asc"]::after {
    content: "▲";
}

tableheader[sort="desc"]::after {
    content: "▼";
}

cell {
    grid-template-rows: max-content;
    justify-content: start;
    align-content: center;
    padding: var(--j2w-space-1) var(--j2w-space-2);
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
    transition: background-color var(--j2w-duration-fast) var(--j2w-ease);
}

cell:hover {
    background-color: var(--j2w-hover-tint);
}

cell[mode=selected] {
    background-color: var(--j2w-selection);
}

/* =========================================
   BUTTON COMPONENTS
   ========================================= */
/* Segmented style: quiet surface at rest, accent-tinted when selected */
togglebutton {
    display: grid;
    justify-content: center;
    align-content: center;
    overflow: hidden;
    /* Segmented toggles are normally built as a row next to buttons and filter
       fields, so they take the shared j2w control height rather than sizing
       themselves from their label. */
    min-height: var(--j2w-control-height);
    line-height: var(--j2w-leading-control);
    padding: var(--j2w-space-1) var(--j2w-space-2);
    border: 1px solid var(--j2w-border);
    border-radius: var(--j2w-radius-md);
    background-color: var(--j2w-surface);
    cursor: pointer;
    transition:
        background-color var(--j2w-duration-base) var(--j2w-ease),
        border-color var(--j2w-duration-base) var(--j2w-ease),
        color var(--j2w-duration-base) var(--j2w-ease);
}

togglebutton:hover {
    background-color: var(--j2w-hover-tint);
}

togglebutton[selected],
togglebutton[selected]:hover {
    background-color: var(--j2w-accent-subtle);
    border-color: color-mix(in srgb, var(--j2w-accent) 40%, transparent);
    color: var(--j2w-accent);
    font-weight: 500;
}

togglebutton[disable],
togglebutton[disable]:hover {
    opacity: 0.5;
    cursor: default;
    pointer-events: none;
}

radiobutton,
checkbox {
    display: grid;
    grid-template-rows: max-content;
    grid-template-columns: max-content minmax(0, 1fr);
    justify-items: start;
    align-items: center;
    gap: var(--j2w-space-2);
    cursor: pointer;
}

/* Slider renders as a native input[type=range]; its styling lives in
   j2w.css (form elements section). */

/* =========================================
   PROGRESS COMPONENTS
   Looping animations are diff-safe under server patches.
   ========================================= */
progressbar {
    display: block;
    position: relative;
    height: 8px;
    min-width: 48px;
    border-radius: var(--j2w-radius-full);
    background-color: var(--j2w-surface-sunken);
    border: 1px solid var(--j2w-border);
    overflow: hidden;
}

progressbar>bar {
    display: block;
    height: 100%;
    width: 0;
    border-radius: var(--j2w-radius-full);
    background-color: var(--j2w-accent);
    transition: width var(--j2w-duration-slow) var(--j2w-ease);
}

progressbar[indeterminate]>bar {
    width: 30%;
    animation: j2w-indeterminate 1.2s var(--j2w-ease) infinite;
}

progressindicator {
    display: block;
    width: 28px;
    height: 28px;
    border-radius: var(--j2w-radius-full);
    background:
        radial-gradient(closest-side, var(--j2w-surface) 74%, transparent 75% 100%),
        conic-gradient(var(--j2w-accent) var(--progress, 0%), var(--j2w-surface-sunken) 0);
}

progressindicator[indeterminate] {
    background: none;
    border: 3px solid var(--j2w-accent-subtle);
    border-top-color: var(--j2w-accent);
    animation: j2w-spin 0.8s linear infinite;
}