librelad 61ed8aa7f2 style(config): match toggle box height to input fields
The config-grid toggle box used the input's 12px vertical padding, but its
24px pill made it render 48px tall vs the inputs' 44px, so it sat too tall
to read as inline. Trim vertical padding to 10px so the box is 44px.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-23 13:21:34 +01:00

1048 lines
25 KiB
CSS

/* Form fields, inputs, checkboxes/tickboxes, input groups. Extracted from style.css. */
/* Form Fields */
.form-field {
display: flex;
flex-direction: column;
gap: 6px;
min-width: 0;
}
.form-label {
display: flex;
align-items: center;
gap: 6px;
font-weight: 500;
color: var(--text-primary, #fff);
font-size: 13px;
}
.required {
color: var(--danger-color);
font-weight: bold;
}
.help-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 14px;
height: 14px;
background: var(--primary-color);
color: var(--text-primary);
border-radius: 50%;
font-size: 9px;
font-weight: bold;
cursor: help;
position: relative;
}
.help-icon:hover::after {
content: attr(title);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: var(--tooltip-bg);
color: var(--tooltip-text);
padding: 4px 8px;
border-radius: 4px;
font-size: 11px;
white-space: nowrap;
z-index: 1000;
margin-bottom: 6px;
min-width: 180px;
text-align: center;
font-weight: normal;
}
.form-input,
.form-select,
.form-textarea {
width: 100%;
padding: 10px;
border: 1px solid var(--border-color);
border-radius: 6px;
color: var(--text-primary, #fff);
font-size: 13px;
transition: all 0.2s ease;
}
.form-input:focus,
.form-select:focus,
.form-textarea:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 2px rgba(74, 144, 226, 0.1);
}
.form-textarea {
resize: vertical;
min-height: 80px;
font-family: inherit;
}
.form-help {
color: var(--text-secondary, #ccc);
font-size: 11px;
font-style: italic;
margin-top: 4px;
}
.checkbox-label.disabled {
opacity: 0.6;
cursor: not-allowed;
}
.checkbox-label.disabled .checkbox-custom {
background: var(--hover-bg);
border-color: var(--border-color);
opacity: 0.5;
}
.checkbox-label.disabled .checkbox-text {
color: var(--text-secondary, #ccc);
}
.form-label.disabled {
color: var(--text-secondary, #ccc);
opacity: 0.6;
}
.form-input.disabled {
background: var(--hover-bg);
border-color: var(--border-color);
opacity: 0.6;
cursor: not-allowed;
}
/* Input Group for Number + Unit */
.input-group {
display: flex;
align-items: stretch;
}
.input-group .form-control {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-right: none;
}
.input-group .form-control:focus {
border-right: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 0.2rem rgba(var(--accent-rgb), 0.25);
}
.input-group-text {
display: flex;
align-items: center;
padding: 10px 12px;
font-size: 14px;
font-weight: 500;
line-height: 1.5;
color: var(--text-color);
text-align: center;
white-space: nowrap;
background-color: var(--input-bg);
border: 1px solid var(--border-color);
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
min-width: 50px;
justify-content: center;
}
.master-toggle .checkbox-label,
.git-master-toggle .checkbox-label {
display: flex;
align-items: center;
font-weight: 600;
font-size: 16px;
cursor: pointer;
width: 100%;
}
/* .master-toggle and .git-master-toggle are section-enable controls
(e.g. backup remote 1, mail config). They inherit the default toggle
visual from .checkbox-custom — no overrides needed here. The
.git-master-toggle block lower in this file remains for legacy
layout (font-weight/sizing on the surrounding label). */
.section-content.disabled .field-group {
opacity: 0.6;
}
/* Themed <select> dropdown. Native rendering on Linux/Firefox honors
the OS dark theme and paints the control black regardless of our
CSS, so we strip the native appearance and supply our own glass
surface + chevron. */
select.form-control {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background-color: rgba(var(--text-rgb), 0.06);
color: var(--text-primary);
border: 1px solid rgba(var(--text-rgb), 0.20);
/* Inline SVG chevron, recoloured via theme text-rgb so it stays
readable on every theme. */
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='rgba(255,255,255,0.7)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
background-repeat: no-repeat;
background-position: right 14px center;
background-size: 16px 16px;
padding-right: 40px;
cursor: pointer;
}
/* <option> elements are drawn by the OS popup, not the page surface.
We can only nudge their colors; the popup chrome itself is platform-
native. Use the theme's solid surface so options stay readable. */
select.form-control option {
background-color: var(--surface-bg-solid);
color: var(--text-primary);
}
select.form-control:hover {
border-color: rgba(var(--accent-rgb), 0.40);
}
select.form-control:focus {
outline: none;
border-color: var(--accent);
background-color: rgba(var(--text-rgb), 0.10);
box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.20);
}
.field-group {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 6px;
}
.field-group label {
font-size: 14px;
font-weight: 500;
color: var(--text-secondary, #ccc);
margin-bottom: 4px;
}
.form-control {
width: 100%;
padding: 12px 16px;
border: 1px solid rgba(var(--text-rgb), 0.2);
border-radius: 8px;
background: rgba(var(--text-rgb), 0.05);
color: var(--text-primary, #fff);
font-size: 14px;
font-family: inherit;
transition: all 0.2s ease;
resize: vertical;
min-height: 44px;
}
.form-control:focus {
outline: none;
border-color: var(--primary-color, var(--accent));
background: rgba(var(--text-rgb), 0.08);
box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.1);
}
.form-control::placeholder {
color: var(--text-secondary, #ccc);
opacity: 0.7;
}
.password-field .form-control {
padding-right: 48px;
}
.field-group label {
font-size: 14px;
font-weight: 500;
color: var(--text-secondary, #ccc);
margin-bottom: 4px;
}
/* Git Configuration Master Toggle */
/* INSTALL_MODE dropdown: narrower than full-width. Both selectors
below are needed because the custom-select.js component wraps the
native <select> in a .custom-select div — we have to constrain the
wrapper (which is what's visually rendered) AND the native select
(which is what's there when JS hasn't enhanced it yet, or when
custom-select is opted out via data-no-enhance). */
.git-master-toggle select.form-control,
.git-master-toggle .custom-select {
width: auto !important;
max-width: 33%;
}
.git-master-toggle .checkbox-text {
font-weight: 600;
font-size: 16px;
margin-left: 8px;
}
.git-master-toggle .checkbox-label {
display: flex;
align-items: center;
cursor: pointer;
padding: 0;
border-radius: 0;
transition: none;
background: transparent;
}
.git-master-toggle .checkbox-label:hover {
background: transparent;
}
/* Toggle Switch Design - Complete override */
.git-master-toggle .checkbox-label input[type="checkbox"] {
display: none !important;
opacity: 0 !important;
position: absolute !important;
}
.git-master-toggle .checkbox-custom {
position: relative;
width: 48px;
height: 24px;
background: var(--border-strong);
border-radius: 24px;
margin-right: 12px;
transition: all 0.3s ease;
cursor: pointer;
border: none !important;
}
.git-master-toggle .checkbox-custom::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
background: white;
border-radius: 50%;
transition: all 0.3s ease;
}
.git-master-toggle .checkbox-label input[type="checkbox"]:checked + .checkbox-custom {
background: var(--primary-color) !important;
border-color: var(--primary-color) !important;
}
.git-master-toggle .checkbox-label input[type="checkbox"]:checked + .checkbox-custom::before {
transform: translateX(24px);
}
.git-master-toggle .checkbox-label input[type="checkbox"]:hover + .checkbox-custom {
}
.git-master-toggle .checkbox-text {
font-size: 14px;
font-weight: 500;
color: var(--text-primary);
line-height: 1.4;
user-select: none;
}
/* Config page checkboxes — mirror the .form-control field box (same radius,
fill and border) so a toggle reads as the same field surface as the inputs
beside it instead of a lighter, slightly-off box. Vertical padding is 10px
(not the input's 12px): the 24px toggle pill is taller than input text, so
the trimmed padding keeps the box at the inputs' 44px height (24 + 10 + 10)
instead of overshooting to 48px. */
.checkbox-label {
display: flex;
align-items: center;
cursor: pointer;
padding: 10px 16px;
min-height: 44px;
border-radius: 8px;
transition: background 0.18s ease, border-color 0.18s ease;
background: rgba(var(--text-rgb), 0.05);
border: 1px solid rgba(var(--text-rgb), 0.20);
}
/* In a multi-column config row the toggle cell only contains the
toggle (no label/help text above it like the input cells do), so
it sits at the top of the row while the inputs underneath their
labels run lower. align-self: end drops the toggle to the bottom
of the grid row so its row aligns with the inputs' row, not the
inputs' labels. */
.config-fields > .checkbox-field {
align-self: end;
}
.checkbox-label:hover {
background: rgba(var(--text-rgb), 0.07);
border-color: rgba(var(--accent-rgb), 0.35);
}
.checkbox-label.disabled {
opacity: 0.6;
cursor: not-allowed;
background: transparent;
border-color: var(--border-color);
}
.checkbox-label.disabled .checkbox-custom {
background: var(--hover-bg);
border-color: var(--border-color);
}
.checkbox-label input[type="checkbox"] {
display: none !important;
opacity: 0 !important;
position: absolute !important;
cursor: pointer;
}
/* ------------------------------------------------------------------
Default checkbox visual = TOGGLE SWITCH.
Most app/config options are binary data settings (Enable X, Auto-Y)
for which a sliding switch reads as "on/off".
The TICKBOX variant (square with check) lives further down, scoped
to .toggle-section and .advanced-toggle-field — those host the
"Show Advanced / Show Unused" UI preferences where a tickbox better
signals "this affects what you see, not the data".
------------------------------------------------------------------ */
.checkbox-custom {
position: relative;
width: 48px;
height: 24px;
flex-shrink: 0;
margin-right: 12px;
background: rgba(var(--text-rgb), 0.20);
border: none;
border-radius: 24px;
cursor: pointer;
transition: background 0.18s ease, box-shadow 0.18s ease;
}
.checkbox-custom::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
background: var(--text-primary);
border-radius: 50%;
transition: transform 0.18s ease;
}
.checkbox-label input[type="checkbox"]:hover + .checkbox-custom {
box-shadow: 0 0 0 4px rgba(var(--accent-rgb), 0.10);
}
.checkbox-label input[type="checkbox"]:checked + .checkbox-custom {
background: var(--accent);
}
.checkbox-label input[type="checkbox"]:checked + .checkbox-custom::before {
transform: translateX(24px);
}
/* ------------------------------------------------------------------
TICKBOX variant — used for "this changes what you see" preferences
like Show Advanced Options / Show Unused Options / Show advanced
settings. Scoped by parent class so the toggle stays the default
everywhere else.
------------------------------------------------------------------ */
.toggle-section .checkbox-custom,
.advanced-toggle-field .checkbox-custom {
width: 20px;
height: 20px;
margin-right: 10px;
background: rgba(var(--text-rgb), 0.05);
border: 1.5px solid rgba(var(--text-rgb), 0.40);
border-radius: 4px;
box-shadow: none;
}
.toggle-section .checkbox-custom::before,
.advanced-toggle-field .checkbox-custom::before {
content: none;
}
.toggle-section .checkbox-custom::after,
.advanced-toggle-field .checkbox-custom::after {
content: '';
position: absolute;
top: 2px;
left: 6px;
width: 5px;
height: 10px;
border: solid var(--text-on-accent, #ffffff);
border-width: 0 2px 2px 0;
transform: rotate(45deg);
opacity: 0;
transition: opacity 0.15s ease;
}
.toggle-section .checkbox-label input[type="checkbox"]:hover + .checkbox-custom,
.advanced-toggle-field .checkbox-label input[type="checkbox"]:hover + .checkbox-custom {
border-color: var(--accent);
box-shadow: none;
}
.toggle-section .checkbox-label input[type="checkbox"]:checked + .checkbox-custom,
.advanced-toggle-field .checkbox-label input[type="checkbox"]:checked + .checkbox-custom {
background: var(--accent);
border-color: var(--accent);
}
.toggle-section .checkbox-label input[type="checkbox"]:checked + .checkbox-custom::after,
.advanced-toggle-field .checkbox-label input[type="checkbox"]:checked + .checkbox-custom::after {
opacity: 1;
}
.checkbox-text {
font-size: 14px;
font-weight: 500;
color: var(--text-primary);
line-height: 1.4;
user-select: none;
}
.group-fields .form-field {
margin-bottom: 20px;
}
.group-fields .form-field:last-child {
margin-bottom: 0;
}
.app-config .form-field {
margin-bottom: 16px;
}
.app-config .form-label {
display: block;
margin-bottom: 6px;
font-weight: 500;
color: var(--text-color);
font-size: 14px;
}
/* App-config inputs share the .form-control recipe used by the standard
config page — translucent theme-aware border + glass fill — so app
config fields stop reading as a near-black slab against the nebula
gradient. */
.app-config .form-input,
.app-config .form-select,
.app-config .config-input,
.config-input {
width: 100%;
padding: 10px 12px;
border: 1px solid rgba(var(--text-rgb), 0.20);
border-radius: 8px;
background: rgba(var(--text-rgb), 0.05);
color: var(--text-primary, #fff);
font-size: 14px;
font-family: inherit;
transition: border-color 0.2s ease, background 0.2s ease;
}
.app-config .form-input:focus,
.app-config .form-select:focus,
.app-config .config-input:focus,
.config-input:focus {
outline: none;
border-color: var(--accent);
background: rgba(var(--text-rgb), 0.08);
}
.app-config .form-input::placeholder,
.app-config .config-input::placeholder,
.config-input::placeholder {
color: var(--text-secondary, #ccc);
opacity: 0.7;
}
.app-config .form-help {
display: block;
margin-top: 4px;
font-size: 12px;
color: var(--text-muted);
line-height: 1.4;
}
/* App Config Checkboxes - EXACT copy of global toggle switch styling */
.app-config .checkbox-label {
display: flex;
align-items: center;
cursor: pointer;
padding: 4px;
border-radius: 6px;
transition: all 0.2s ease;
background: #0000;
border: 1px solid transparent;
}
.app-config .checkbox-label:hover {
/* background: rgba(var(--text-rgb),0.05); */
}
.app-config .checkbox-label.disabled {
opacity: 0.6;
cursor: not-allowed;
background: transparent;
border-color: var(--border-color);
}
.app-config .checkbox-label.disabled .checkbox-custom {
background: var(--hover-bg);
border-color: var(--border-color);
}
.app-config .checkbox-label.disabled .checkbox-text {
color: var(--text-secondary, #ccc);
}
.app-config .checkbox-label:hover .checkbox-text {
color: var(--text-primary);
}
.app-config .checkbox-text {
font-size: 14px;
font-weight: 500;
color: var(--text-primary);
line-height: 1.4;
user-select: none;
}
.app-config .checkbox-label input[type="checkbox"] {
display: none !important;
opacity: 0 !important;
position: absolute !important;
cursor: pointer;
}
.app-config .checkbox-custom {
position: relative;
width: 48px;
height: 24px;
background: var(--border-strong);
border-radius: 24px;
margin-right: 12px;
transition: all 0.3s ease;
cursor: pointer;
border: none;
}
.app-config .checkbox-custom::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
background: white;
border-radius: 50%;
transition: all 0.3s ease;
}
.app-config .checkbox-label input[type="checkbox"]:hover + .checkbox-custom {
}
.app-config .checkbox-label input[type="checkbox"]:checked + .checkbox-custom {
background: var(--primary-color);
border-color: var(--primary-color);
}
.app-config .checkbox-label input[type="checkbox"]:checked + .checkbox-custom::before {
transform: translateX(24px);
}
/* Field Group Styling for Domain Blocks */
.domain-building-block .field-group {
margin: 0;
width: 100%;
display: flex;
flex-direction: column;
}
.domain-building-block .field-label {
display: block;
margin-bottom: 6px;
font-weight: 500;
color: var(--text-color);
font-size: 14px;
}
.domain-building-block .form-control {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--border-color);
border-radius: 4px;
background: var(--input-bg);
color: var(--text-color);
font-size: 14px;
transition: border-color 0.3s ease;
box-sizing: border-box;
}
.domain-building-block .form-control:focus {
outline: none;
border-color: var(--primary-color, var(--accent));
box-shadow: 0 0 0 2px rgba(var(--accent-rgb), 0.25);
}
/* Toggle-specific spacing */
.checkbox-label.master-toggle {
padding: 20px;
}
/* Enhanced field styling */
.form-field {
position: relative;
}
.form-label {
display: flex;
align-items: center;
gap: 6px;
font-weight: 500;
margin-bottom: 6px;
}
.required {
color: var(--error-color);
font-weight: 600;
}
.help-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 16px;
height: 16px;
background: var(--primary-color);
color: var(--text-primary);
border-radius: 50%;
font-size: 10px;
font-weight: bold;
cursor: help;
margin-left: 4px;
}
.form-help {
display: block;
margin-top: 4px;
font-size: 11px;
color: var(--text-secondary);
font-style: italic;
}
/* "Show Advanced / Show Unused" UI-preference wrapper. Glass card that
reads on every theme — replaces an older recipe that hardcoded
var(--surface-bg-solid) (solid dark navy on nebula) plus a near-white
#f9f9f9 hover, which made the label invisible on dark themes. */
.toggle-section .checkbox-label {
display: flex;
align-items: flex-start;
cursor: pointer;
width: 100%;
padding: 14px 16px;
background: rgba(var(--text-rgb), 0.05);
border: 1px solid rgba(var(--text-rgb), 0.10);
border-radius: 10px;
box-shadow: inset 0 1px 0 rgba(var(--text-rgb), 0.04);
transition: background 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
}
.toggle-section .checkbox-label:hover {
background: rgba(var(--text-rgb), 0.08);
border-color: rgba(var(--accent-rgb), 0.40);
box-shadow: inset 0 1px 0 rgba(var(--text-rgb), 0.06);
}
/* .toggle-section .checkbox-custom intentionally NOT redefined here.
The shared tickbox styling earlier in this file already scopes the
square-check visual to .toggle-section, so adding another rule here
would just override it. */
.toggle-section .checkbox-text {
font-weight: 600;
color: var(--text-primary);
font-size: 16px;
margin-bottom: 4px;
}
.toggle-section .checkbox-description {
font-size: 13px;
color: var(--text-secondary);
line-height: 1.4;
}
/* Red-flash highlight for required-but-empty fields when the user clicks
Install. Cleared on the next input/change. Native title attribute on the
element provides the "Required" tooltip on hover. */
.field-required-error {
border: 1.5px solid var(--status-danger) !important;
box-shadow: 0 0 0 3px rgba(var(--status-danger-rgb), 0.20);
animation: requiredFlash 0.6s ease-in-out 2;
background: rgba(var(--status-danger-rgb), 0.06) !important;
}
/* ============================================================
Custom <select> component (js/system/custom-select.js).
Native <select> popups are drawn by the OS and ignore CSS for the
popup chrome. This component visually replaces the native select
while keeping it in the DOM for form submission / change events.
============================================================ */
.custom-select {
position: relative;
width: 100%;
display: inline-block;
}
/* The native <select> stays in the DOM (so forms submit + JS reading
.value continues to work) but is hidden behind the styled button. */
.custom-select-native {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
opacity: 0;
pointer-events: none;
z-index: -1;
}
.custom-select-button {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 12px 16px;
background: rgba(var(--text-rgb), 0.06);
border: 1px solid rgba(var(--text-rgb), 0.20);
border-radius: 8px;
color: var(--text-primary);
font-size: 14px;
font-family: inherit;
text-align: left;
cursor: pointer;
transition: background 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
}
.custom-select-button:hover:not(:disabled) {
border-color: rgba(var(--accent-rgb), 0.40);
}
.custom-select-button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.custom-select.is-open .custom-select-button {
border-color: var(--accent);
background: rgba(var(--text-rgb), 0.10);
box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.20);
}
.custom-select-label {
flex: 1;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.custom-select-arrow {
display: inline-flex;
flex-shrink: 0;
color: rgba(var(--text-rgb), 0.70);
transition: transform 0.18s ease;
}
.custom-select.is-open .custom-select-arrow {
transform: rotate(180deg);
color: var(--accent);
}
/* Popup — fixed-positioned (top/left/width set by JS in
custom-select.js > positionPopup) so the dropdown escapes any
ancestor with overflow: hidden, e.g. .eo-modal-content. z-index
is above eo-modal (1100) so it floats over modals too. */
.custom-select-popup {
position: fixed;
z-index: 1200;
max-height: 280px;
overflow-y: auto;
padding: 6px;
background: var(--surface-bg-solid, var(--bg-primary));
border: 1px solid rgba(var(--text-rgb), 0.16);
border-radius: 10px;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(var(--text-rgb), 0.06);
backdrop-filter: blur(14px) saturate(140%);
-webkit-backdrop-filter: blur(14px) saturate(140%);
animation: customSelectIn 0.12s ease-out;
}
.custom-select-popup.flip-up {
transform-origin: bottom center;
}
@keyframes customSelectIn {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
.custom-select-popup.flip-up {
animation-name: customSelectInUp;
}
@keyframes customSelectInUp {
from { opacity: 0; transform: translateY(4px); }
to { opacity: 1; transform: translateY(0); }
}
.custom-select-option {
padding: 9px 12px;
border-radius: 6px;
cursor: pointer;
color: var(--text-primary);
font-size: 14px;
line-height: 1.3;
user-select: none;
transition: background 0.12s ease, color 0.12s ease;
position: relative;
}
.custom-select-option:hover,
.custom-select-option.is-focused {
background: rgba(var(--accent-rgb), 0.15);
color: var(--accent);
}
.custom-select-option.is-selected {
background: rgba(var(--accent-rgb), 0.22);
color: var(--accent);
font-weight: 600;
}
.custom-select-option.is-selected::after {
content: '';
position: absolute;
top: 50%;
right: 12px;
width: 4px;
height: 8px;
margin-top: -6px;
border: solid var(--accent);
border-width: 0 2px 2px 0;
transform: rotate(45deg);
}
.custom-select-option.is-disabled {
opacity: 0.4;
cursor: not-allowed;
}
/* Themed scrollbar for the popup. */
.custom-select-popup::-webkit-scrollbar {
width: 8px;
}
.custom-select-popup::-webkit-scrollbar-track {
background: transparent;
}
.custom-select-popup::-webkit-scrollbar-thumb {
background: rgba(var(--text-rgb), 0.20);
border-radius: 4px;
}
.custom-select-popup::-webkit-scrollbar-thumb:hover {
background: rgba(var(--accent-rgb), 0.40);
}
/* ============================================================
Custom number stepper (js/system/custom-number.js).
Replaces the OS spin-buttons on <input type="number"> with themed
up/down chevrons that read consistently across browsers/themes.
============================================================ */
/* Hide native browser spin buttons. */
.custom-number-input::-webkit-outer-spin-button,
.custom-number-input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
.custom-number-input {
-moz-appearance: textfield;
}
.custom-number {
position: relative;
display: inline-flex;
width: 100%;
align-items: stretch;
}
/* The input itself stretches to fill, leaving room for the controls. */
.custom-number .custom-number-input {
flex: 1;
min-width: 0;
padding-right: 36px;
}
.custom-number.is-disabled {
opacity: 0.6;
}
.custom-number-controls {
position: absolute;
top: 4px;
right: 4px;
bottom: 4px;
display: flex;
flex-direction: column;
width: 24px;
border-radius: 6px;
overflow: hidden;
background: rgba(var(--text-rgb), 0.05);
}
.custom-number-btn {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: none;
color: rgba(var(--text-rgb), 0.65);
cursor: pointer;
padding: 0;
margin: 0;
transition: background 0.12s ease, color 0.12s ease;
}
.custom-number-btn:hover:not(:disabled) {
background: rgba(var(--accent-rgb), 0.20);
color: var(--accent);
}
.custom-number-btn:active:not(:disabled) {
background: rgba(var(--accent-rgb), 0.35);
}
.custom-number-btn:disabled,
.custom-number-btn.is-disabled {
opacity: 0.30;
cursor: not-allowed;
}
/* Subtle divider between up/down. */
.custom-number-up {
border-bottom: 1px solid rgba(var(--text-rgb), 0.08);
}