/*******************************************************************************
 * Copyright 2026 - Raul Herreros - Amtiri SpA
 *
 * Application-level corrections layered on top of j2w.css and fx2web.css.
 * Only rules that cannot reasonably live in the shared libraries belong here.
 *
 * @author Raul Herreros
 ******************************************************************************/

/*
 * The modal layer must always paint above the application panel.
 *
 * j2w.css gives <modals> position:fixed, and fixed positioning always creates a stacking context,
 * so the whole modal layer stacks as one box at z-index auto. The application panel is a sibling
 * that comes later in <body>, which means every element inside it that forms its own stacking
 * context - unselected workspace tabs through fx2web.css opacity:0.55, and the tab close buttons
 * through their own opacity - is painted after the modal layer and shows through an open dialog,
 * close button included. Raising <modals> instead of the dialog is what fixes it: a z-index on the
 * dialog only orders it inside the layer it is already trapped in.
 *
 * This only becomes visible once a dialog leaves the browser top layer, which happens as soon as a
 * second dialog opens: patching <modals> re-attaches the first dialog, and re-insertion does not
 * restore top-layer status.
 */
modals {
    z-index: 1000;
}

/*
 * Branding hooks left unstyled on purpose.
 *
 * .site-logo carries no rule here. It marks the four image nodes that render
 * application.bigLogo / application.smallLogo - login, mobile login, workspace header, mobile
 * header - so a deployment theme loaded from application.theme can give its own mark whatever
 * treatment it needs: a plaque for a logo drawn white-on-dark, a size correction, an inversion.
 * The default Amtiri mark needs none of that, which is why the class stays empty rather than
 * carrying a neutral default that every theme would then have to undo.
 */

/*
 * Site components.
 *
 * These were inline setStyles() strings carrying hard-coded pixels and colors, which the redesign
 * made wrong twice over: the literals ignored the token scale, and the fixed greys did not invert
 * in dark mode. Expressed as classes they follow the theme and stay consistent between the desktop
 * and mobile entry points.
 */

/*
 * Risk colors.
 *
 * The token set is blue/red only, but this app needs a third signal: an action that is safe to
 * take. Green commits, red risks losing work or stops the plant, blue is everything else.
 *
 * --site-safe stays a full-strength green because the run-state indicator paints with it; the
 * -subtle and -text pairs are what the buttons use, mirroring how tokens.css splits --j2w-danger
 * from --j2w-danger-subtle.
 */
:root {
    --site-safe: light-dark(#16A34A, #22C55E);
    --site-safe-subtle: light-dark(#F0FDF4, color-mix(in srgb, #22C55E 15%, transparent));
    --site-safe-text: light-dark(#15803D, #4ADE80);
    --site-status-running: var(--site-safe);
    /* Grey, not red: stopped is a state an engine spends much of its life in, not a fault to be alarmed about. */
    --site-status-stopped: light-dark(#94A3B8, #475569);
}

/*
 * Buttons are tinted, never filled.
 *
 * A solid fill makes every button shout, and with three meanings in play (commit / discard /
 * neutral) a toolbar of solid buttons reads as an alarm. Each variant instead gets a very light
 * wash of its own hue, a border at the same hue, and its text in the saturated version - so the
 * meaning is carried by colour while the weight stays even across the row.
 *
 * All three share one shape; only the hue changes. The workspace's own tab close button is not one
 * of them: it is chrome-free on purpose, and workspace.css styles it.
 */
button.j2w-quiet,
button.site-safe,
button.site-danger,
button.site-danger-quiet {
    border-width: 1px;
    border-style: solid;
    box-shadow: none;
}

/* Neutral - light blue. */
button.j2w-quiet {
    background-color: var(--j2w-accent-subtle);
    border-color: color-mix(in srgb, var(--j2w-accent) 30%, transparent);
    color: var(--j2w-accent);
}

button.j2w-quiet:hover {
    background-color: color-mix(in srgb, var(--j2w-accent) 18%, transparent);
    border-color: color-mix(in srgb, var(--j2w-accent) 50%, transparent);
}

/* Commits the change - light green: Save, Accept, Apply, Start. */
button.site-safe {
    background-color: var(--site-safe-subtle);
    border-color: color-mix(in srgb, var(--site-safe) 35%, transparent);
    color: var(--site-safe-text);
}

button.site-safe:hover {
    background-color: color-mix(in srgb, var(--site-safe) 18%, transparent);
    border-color: color-mix(in srgb, var(--site-safe) 55%, transparent);
}

/* Discards work or stops the plant - light red: Cancel, Stop, Delete, Surrender. */
button.site-danger,
button.site-danger-quiet {
    background-color: var(--j2w-danger-subtle);
    border-color: color-mix(in srgb, var(--j2w-danger) 35%, transparent);
    color: var(--j2w-danger);
}

button.site-danger:hover,
button.site-danger-quiet:hover {
    background-color: color-mix(in srgb, var(--j2w-danger) 18%, transparent);
    border-color: color-mix(in srgb, var(--j2w-danger) 55%, transparent);
}

/* The run-state indicator is a status lamp, not a control, so it stays fully saturated. */
.site-status-running {
    background-color: var(--site-status-running);
}

.site-status-stopped {
    background-color: var(--site-status-stopped);
}

/*
 * The workspace chrome - header bar, action chips, avatar, tab close, console lines - is no longer
 * declared here. It came from com.amtiri:workspace with the frame itself, as the wks-* layer in
 * workspace.css, which this file is loaded after and may still override with a plain selector.
 */

/*
 * Dashboard fullscreen.
 *
 * A fullscreened element is painted on the browser's own black backdrop and keeps its normal box
 * size, so without these rules the dashboard would sit as a small panel on black. Filling the
 * viewport and repainting the surface is what actually makes the mode useful on a wall display.
 *
 * ':-webkit-full-screen' is a legacy alias, not a standard pseudo-class, so each rule below is
 * written out twice rather than grouped: a browser that does not recognise one selector in a
 * selector list drops the whole rule, which would take the standard ':fullscreen' down with it.
 */
.site-dashboard:fullscreen {
    width: 100vw;
    height: 100vh;
    padding: var(--j2w-space-2);
    background-color: var(--j2w-bg);
}

.site-dashboard:-webkit-full-screen {
    width: 100vw;
    height: 100vh;
    padding: var(--j2w-space-2);
    background-color: var(--j2w-bg);
}

/*
 * The toggle flips its own glyph from the fullscreen state itself rather than from a flag kept in
 * script - so leaving fullscreen by pressing Escape, which never runs our click handler, still
 * leaves the button showing the correct action.
 *
 * '!important' is required, not decorative: the glyph carries its default '--icon' as an inline
 * style attribute (DashboardView.fxml), and an inline declaration outranks every selector in a
 * stylesheet. Custom properties obey that same cascade, so without this the exit glyph is computed
 * and then discarded, and the button keeps showing "enter fullscreen" while already fullscreen.
 *
 * The URL is relative to this stylesheet (/resources/), not $APP$ - that token is only expanded in
 * J2Web-generated markup, never in a statically served file.
 */
.site-dashboard:fullscreen .site-fullscreen-glyph {
    --icon: url(../com/amtiri/data/resources/icons/fullscreen-exit.svg) !important;
}

.site-dashboard:-webkit-full-screen .site-fullscreen-glyph {
    --icon: url(../com/amtiri/data/resources/icons/fullscreen-exit.svg) !important;
}

/* Hairline separating the view action from the zoom group above it. */
.site-dashboard-tools-rule {
    height: 1px;
    flex: none;
    margin: var(--j2w-space-1) 0;
    background-color: var(--j2w-border);
}

/* =========================================
   THE ASSIGNED / AVAILABLE PICK LISTS

   Two lists side by side, a row moving between them on a double-click. Both
   are laid out by the FXML; what they need from here is a floor.

   A listview has no intrinsic height, so one with nothing in it is drawn as
   its own border - a 10px line under a heading. That is the state these lists
   are in exactly when they most need to look like a target: everything has
   been assigned, so Available is empty, and the panel appears broken rather
   than finished. The floor is roughly six rows, enough that a list reads as a
   container whether it holds nothing or scrolls.
   ========================================= */
.site-picklist {
    min-height: 160px;
    /* A grid item's automatic minimum size is its content, which is what let the
       wider list push the narrower one out of its share of the row. */
    min-width: 0;
}

/* =========================================
   THE DASHBOARD EDITOR'S WORK AREA

   A sheet on a table. The scroll pane around the canvas used to be the same
   white as the canvas itself, so the edge of the work area was invisible: a
   component dragged past it looked exactly like one still inside, and the only
   way to find the boundary was to save and see what had gone missing.

   The table is the sunken surface the rest of the product already uses for the
   ground behind content, and the sheet keeps its white and gains a hairline and
   a shadow to lift off it. Both, rather than one or the other: the tone
   separation alone is subtle at a glance on a bright screen, and a line alone
   reads as a table border rather than as the edge of the artboard.
   ========================================= */
.site-dashboard-pasteboard {
    background-color: var(--j2w-surface-sunken);
}

/*
 * outline, not border: components on this canvas are absolutely positioned at
 * the coordinates they were authored with, and a border would take part in the
 * box and shift every one of them by a pixel. An outline is drawn outside the
 * box and changes no geometry.
 */
.site-dashboard-canvas {
    outline: 1px solid var(--j2w-border-strong);
    box-shadow: var(--j2w-shadow-2);
}

/* Mobile dashboard tile: full-width touch target on the raised surface. */
.site-mobile-tile {
    width: 100%;
    padding: var(--j2w-space-3);
    background-color: var(--j2w-surface-raised);
    border: 1px solid var(--j2w-border);
    border-radius: var(--j2w-radius-md);
}

.site-mobile-tile:hover {
    box-shadow: inset 0 0 0 9999px var(--j2w-hover-tint);
}

/* =========================================
   THE ORCHESTER DIAGRAM

   The nodes of the Orchester Panel are SVG, and SVG has no theme of its own:
   every fill and stroke on that sheet reads one of the tokens below, so the
   diagram follows the reader's theme instead of carrying two hard-coded
   palettes in Java. They live here, next to the run-state colors the same
   screen already uses, and are mirrored - light values only - in
   OrchesterExport, which has to inline them because an exported .svg has no
   access to this stylesheet.

   Module and variable are distinguished by hue rather than by shape alone:
   both are rounded boxes on purpose (the wiring is what the eye should follow,
   not the outlines), so colour is what tells the two kinds apart at a glance.
   ========================================= */
:root {
    /*
     * Opaque, in both themes. Links are drawn under the boxes, and a fill mixed into transparency let every wire
     * that passed behind a module show through it - which read as the wire going somewhere it does not. The dark
     * values are mixed into the surface colour instead, which gives the same tint with nothing showing through.
     */
    --site-node-module-fill: light-dark(#EEF2FF, color-mix(in srgb, #6366F1 22%, #0F172A));
    --site-node-module-stroke: light-dark(#4F46E5, #A5B4FC);
    --site-node-variable-fill: light-dark(#ECFDF5, color-mix(in srgb, #10B981 20%, #0F172A));
    --site-node-variable-stroke: light-dark(#047857, #6EE7B7);
    --site-node-text: var(--j2w-text);
    --site-node-muted: var(--j2w-text-secondary);
    --site-node-port: light-dark(#475569, #CBD5E1);
    /*
     * A trigger is the port that makes something run, so it is the one that carries a colour of its own: dark red,
     * which also keeps it clear of the brighter red an error uses. The dark-theme value is the same hue lifted until
     * it reads on a dark surface - darkred itself all but disappears there.
     */
    --site-node-trigger: light-dark(#8B0000, #E06C6C);
    /* One colour for everything wrong: the outline of the node, and the hollow glyph of the port at fault. */
    --site-node-error: light-dark(#DC2626, #F87171);
    --site-node-link: light-dark(#64748B, #94A3B8);
    /* A trigger link is blue: red at the scale of a wire crossing a whole sheet is more alarm than it deserves. */
    --site-node-link-trigger: light-dark(#2563EB, #60A5FA);
    --site-node-peer-fill: light-dark(#FDF4FF, color-mix(in srgb, #D946EF 20%, #0F172A));
    --site-node-peer-stroke: light-dark(#A21CAF, #F0ABFC);
    /* A module that is configured but not running: drained of hue, never faded - see the note on transparency above. */
    --site-node-disabled-fill: light-dark(#F1F5F9, #1E293B);
    --site-node-disabled-stroke: light-dark(#94A3B8, #64748B);
    --site-node-selected: light-dark(#2563EB, #60A5FA);
    /* A module's status tile. The tile is a tint, which compresses hue, so these are chosen to stay apart from
       each other once tinted - an amber warning beside a red error read as two warm smudges. Measured in
       OrchesterStatusBadgeTest (light) and StatusPaletteTest (dark). */
    --site-node-status-on: light-dark(#16A34A, #4ADE80);
    --site-node-status-warning: light-dark(#EAB308, #FACC15);
    --site-node-status-error: light-dark(#DC2626, #EF4444);
    --site-node-status-off: light-dark(#94A3B8, #64748B);
}


/*
 * The sheet is delimited by its edge, not by its shade.
 *
 * Darkening the ground was the cheap way to make the canvas findable and it cost more than it bought: the nodes
 * are pale boxes with pale fills, and a grey field behind them eats the contrast they rely on to read as objects
 * lying on something. A border draws the same boundary without touching anything inside it.
 *
 * The dot grid is what the shade was really for - saying "work surface" rather than "page". It is drawn from the
 * border colour at one pixel, so it is texture rather than tone, and `background-attachment: local` scrolls it
 * with the sheet instead of pinning it to the viewport: a node dropped on a dot stays on that dot. The 16px step
 * is twice OrchesterMetrics.GRID and divides SHEET_PADDING, so the grid the eye sees and the grid a node snaps
 * to are the same grid.
 */
.site-orchester-pasteboard {
    background-color: var(--j2w-surface);
    background-image: radial-gradient(circle at 1px 1px, var(--j2w-border) 1px, transparent 0);
    background-size: 16px 16px;
    background-attachment: local;
    border: 1px solid var(--j2w-border);
    border-radius: var(--j2w-radius-lg);
    box-shadow: var(--j2w-shadow-1);
}

/*
 * Everything around the sheet is the same card: the toolbar above it, the panels of the rail beside it, the action
 * strip below, and in the tabular view the table and the value strip under that.
 *
 * They were four different things before - two bare bands with no edge at all, and panels carrying `j2w-border`
 * `j2w-rounded` - so the screen read as controls scattered on a page rather than as one instrument.
 *
 * The definition is not invented here: it is what a `titledpane` already draws itself as - same surface, same
 * border token, same corner, same one-pixel lift. The rail's panels are titled panes, so the way to make a bar
 * look like one is to say what one already says. Those panels also used to carry `j2w-border` and `j2w-rounded`,
 * which look like they agree and do not: the utility class paints `--j2w-color-border`, a flat 33% grey, over the
 * `--j2w-border` the element had chosen. That override is gone, and every surface on this screen now resolves to
 * one edge colour.
 */
.site-orchester-chrome {
    background-color: var(--j2w-surface);
    border: 1px solid var(--j2w-border);
    border-radius: var(--j2w-radius-lg);
    box-shadow: var(--j2w-shadow-1);
}

/* A hairline between groups of toolbar buttons - Tabular/Diagram, then the sheet actions, then history. */
.site-toolbar-separator {
    width: 1px;
    align-self: stretch;
    margin: var(--j2w-space-1) var(--j2w-space-2);
    background-color: var(--j2w-border);
}

/*
 * The active half of the Tabular/Diagram pair. A quiet button gives no persistent state, and which view
 * you are looking at has to be readable without moving the pointer over the toolbar.
 */
.site-toggle-on {
    background-color: var(--j2w-hover-tint);
    box-shadow: inset 0 -2px 0 0 var(--j2w-accent);
}

/*
 * The catalog chips.
 *
 * A chip is a small copy of the node it creates - same icon, same fill, same border and radius - so the rail reads
 * as a shelf of the things themselves rather than a column of buttons, and doubles as the legend for the sheet.
 * The grab cursor and the lift on hover are the only affordance a chip has: nothing about a coloured label says
 * "drag me" on its own.
 */
.site-orchester-chip {
    display: flex;
    align-items: center;
    gap: var(--j2w-space-2);
    padding: var(--j2w-space-2) var(--j2w-space-3);
    border: 1.5px solid var(--j2w-border);
    border-radius: 6px;
    background-color: var(--j2w-surface-raised);
    cursor: grab;
    user-select: none;
    font-size: 13px;
}

.site-orchester-chip .j2w-icon {
    width: 18px;
    height: 18px;
    flex: none;
}

.site-orchester-chip:hover {
    box-shadow: var(--j2w-shadow-2);
}

.site-orchester-chip:active {
    cursor: grabbing;
}

.site-chip-module {
    border-color: var(--site-node-module-stroke);
    background-color: var(--site-node-module-fill);
}

.site-chip-variable {
    border-color: var(--site-node-variable-stroke);
    background-color: var(--site-node-variable-fill);
}

.site-chip-peer {
    border-color: var(--site-node-peer-stroke);
    background-color: var(--site-node-peer-fill);
}

/*
 * Icon and label both in the reading colour, exactly as on a node: a chip is meant to be the thing it creates, and
 * an icon tinted here but black there is the one place the two would stop matching.
 */
.site-orchester-chip {
    color: var(--site-node-text);
}


/*
 * Rearranging the orchester diagram, eased.
 *
 * Pressing Arrange can move every node at once, and a diagram that teleports into a new shape has to be re-read
 * from scratch: nothing tells the eye that the box now on the left is the one that was in the middle. Easing the
 * move keeps each node identifiable while it travels, so the operator watches the same diagram settle rather than
 * being handed a different one.
 *
 * A node is positioned by a transform on its group, and a link by its path data, precisely so that both are CSS
 * properties the browser can interpolate. Path interpolation is not universal - where it is unsupported the wires
 * snap while the boxes glide, which is a graceful way to lose the effect rather than a broken one.
 */
.site-orchester-node {
    transition: transform 380ms cubic-bezier(0.4, 0, 0.2, 1);
}

.site-orchester-link {
    transition: d 380ms cubic-bezier(0.4, 0, 0.2, 1);
}

/*
 * Dragging is the one move that must not be eased: a node has to sit under the pointer that is carrying it, and a
 * third of a second of catch-up reads as the screen lagging rather than as motion.
 */
.site-orchester-dragging .site-orchester-node,
.site-orchester-dragging .site-orchester-link {
    transition: none;
}

/* Motion is decoration here; the diagram is complete without it. */
@media (prefers-reduced-motion: reduce) {
    .site-orchester-node,
    .site-orchester-link {
        transition: none;
    }
}

/*
 * The engine's run controls, at the head of the Configuration menu.
 *
 * Above the screen that configures it rather than inside it: whether the plant is running is the first thing an
 * operator wants to know, and it should not be behind a tab that has to be opened to see it. The indicator itself is
 * styled from Java - see SiteMenu.refreshOrchesterRun for why a rule here would not have been safe to rely on.
 */
.site-orchester-run {
    padding: var(--j2w-space-1) 0 var(--j2w-space-2) 0;
}


/* =========================================
   A PANEL SHOWN OVER A DASHBOARD

   A panel is rendered by the same view class as a dashboard, because it is the
   same thing: components on a canvas, subscribed to the engine. What it is not
   is a screen - it has no zoom rail, it is not scrolled, and it is placed and
   sized by whatever opened it. So the chrome a screen needs is taken away here
   rather than by building a second view that would have to be kept in step with
   the first.

   It paints nothing of its own: no surface and no outline. Both belong to the
   panel, whose background its author sets and can make transparent - a colour or
   an edge drawn here would sit over the dashboard whatever the panel asked for,
   and an outline in particular ends up framing an empty box the moment the panel
   is transparent, which is exactly when there is least to frame.

   A shadow is kept, because a popup still has to read as something laid over the
   picture rather than as part of it, and a shadow says that without drawing an
   edge of its own. Clipping is kept too: a panel shows what fits the size it was
   given and does not spill past it.
   ========================================= */
.site-dashboard-popup {
    width: 100%;
    height: 100%;
    padding: 0;
    background-color: transparent;
    border: none;
    border-radius: var(--j2w-radius-md);
    box-shadow: var(--j2w-shadow-3, var(--j2w-shadow-2));
    overflow: hidden;
}

/* The scroll pane inside a popup is a wrapper, not a viewport: the popup is
   exactly as big as the panel it shows, so anything to scroll would be a
   mistake in the offsets rather than something the operator should chase.
   Nothing is styled for it here - its padding is inline and its surface is a
   class, so DashboardView.showAsPanel takes both off the node itself. */

/* =========================================
   SWITCH

   Drawn from the toggle's own 'selected' attribute, so the knob slides on the
   same state change that the server patches in - no script, no frame loop, and
   the animation survives a repaint that replaces the element's attributes.

   The knob is a pseudo-element rather than a child node: J2Web patches the DOM
   from the server, and a child it does not know about is a child it may remove.
   ========================================= */
togglebutton.amtiri-switch {
    position: relative;
    display: block;
    min-height: 0;
    padding: 0;
    border: 1px solid var(--j2w-border-strong);
    border-radius: 999px;
    /* The two state colours are settings on the widget, handed over as custom
       properties - a switch that names neither falls back to the accent and the
       sunken surface the rest of the product uses. See FieldSwitch. */
    background-color: var(--amtiri-switch-off, var(--j2w-surface-sunken));
    cursor: pointer;
    /* Both the knob's size and its travel are read off this box, so a switch
       dragged to any size on the canvas stays a pill with a round knob in it. */
    container-type: size;
    transition:
        background-color var(--j2w-duration-base) var(--j2w-ease),
        border-color var(--j2w-duration-base) var(--j2w-ease);
}

/* Sized in cqh - a share of the track's height - rather than in per cent: a
   percentage on a transform would resolve against the knob itself, and the
   travel has to be measured against the track. */
togglebutton.amtiri-switch::after {
    content: "";
    position: absolute;
    top: 8cqh;
    left: 8cqh;
    width: 84cqh;
    height: 84cqh;
    border-radius: 50%;
    background-color: var(--j2w-surface-raised, #fff);
    box-shadow: var(--j2w-shadow-1);
    transition: transform var(--j2w-duration-base) var(--j2w-ease);
}

togglebutton.amtiri-switch[selected],
togglebutton.amtiri-switch[selected]:hover {
    background-color: var(--amtiri-switch-on, var(--j2w-accent));
    border-color: var(--amtiri-switch-on, var(--j2w-accent));
}

/* The width of the track less its height: what is left once the knob and the
   equal inset at either end are taken out of it. */
togglebutton.amtiri-switch[selected]::after {
    transform: translateX(calc(100cqw - 100cqh));
}

@media (prefers-reduced-motion: reduce) {
    togglebutton.amtiri-switch,
    togglebutton.amtiri-switch::after {
        transition: none;
    }
}

/* =========================================
   DASHBOARD POPUP - FADE

   The box a panel is placed in fades, not the panel inside it: the box is the
   popup as the operator sees it, shadow and corners included, so all of it
   goes down together.

   Fading in is an animation rather than a transition because there is no state
   to change from - the element simply appears, and an animation is what runs on
   an element that has just been inserted. That also means a panel fades in
   however it was opened, a formula included, with nothing to wire up per route.

   Fading out cannot work that way: the element is gone the moment the server
   removes it, and there is nothing left to animate. So a closing panel is
   marked here first and the removal waits for this to finish - see PopupFade
   and PopupHover, which own that wait.

   The duration comes from the element, written onto it by DashboardView from
   the same constant the wait is measured with, so the two cannot drift apart.
   The fallback is only for a popup rendered before that property existed.
   ========================================= */
.site-dashboard-popup-frame {
    animation: site-dashboard-popup-in var(--site-popup-fade, 160ms) var(--j2w-ease) both;
}

.site-dashboard-popup-frame.site-dashboard-popup-closing {
    animation: site-dashboard-popup-out var(--site-popup-fade, 160ms) var(--j2w-ease) both;
}

@keyframes site-dashboard-popup-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes site-dashboard-popup-out {
    from { opacity: 1; }
    to   { opacity: 0; }
}

/* The panel still closes on a browser told to reduce motion - the removal is
   timed, not hung off the animation ending - it simply goes at once instead of
   fading. */
@media (prefers-reduced-motion: reduce) {
    .site-dashboard-popup-frame,
    .site-dashboard-popup-frame.site-dashboard-popup-closing {
        animation: none;
    }
}

/* =========================================
   SIGN-IN AND USERS

   The notice shown instead of a sign-in card while no identity provider can
   take a sign-in, and the two read-only marks the user editor carries: where
   the account comes from, and which provider lists it as an administrator.
   ========================================= */
.site-no-authenticator-message {
    text-align: center;
    color: var(--j2w-text-secondary);
}

.site-user-source,
.site-user-administrator {
    font-size: var(--j2w-text-sm);
    color: var(--j2w-text-secondary);
}
