@layer base { /* Forms: input types, .cbi-value row layout, focus/disabled/readonly/invalid states. */ fieldset { margin-bottom: var(--fs-space-2); padding-top: var(--fs-space-2); } /* size + ink: theme/30-tables.css (legend) — absorbed */ fieldset legend { display: block; line-height: 1; padding-top: var(--fs-space-5); } /* Stays in BASE: docs/css.md "Forms: control typography stays in base, on purpose". select is * excluded, and an input's size is theme/60-inputs.css's --fs-type-field. */ label, input, button { font-family: var(--fs-font-sans); font-size: var(--fs-type); font-weight: var(--fs-weight-normal); line-height: normal; } .cbi-value { display: flex; flex-wrap: wrap; align-items: baseline; } .cbi-value-field { margin-inline-start: var(--fs-space-5); /* logical: LuCI ships four RTL languages */ flex: 1; min-width: 0; /* else a nested table or one long value pushes the row out of the card */ } /* size + ink: theme/60-inputs.css (.cbi-value-title) — absorbed. Left: label column geometry. */ .cbi-value label.cbi-value-title { padding-top: var(--fs-space-1); /* lands the label's first baseline on the field's */ flex: 0 0 11.25rem; /* column WIDTH (longest option label), not on the 4px step scale */ text-align: end; /* towards the field — not base/95-luci.css's physical .left/.right/.center */ /* docs/css.md "Forms: the label column's min-width: 0 survives the responsive layer" — * stated here, not in theme/90-responsive.css. */ min-width: 0; } .cbi-value > .cbi-section, .cbi-value > .cbi-tblsection { width: 100%; } label > input[type="checkbox"], label > input[type="radio"] { vertical-align: text-top; } label[for] { cursor: pointer; } /* Shared field box (210px x control-height, #localtime widening, per-widget escapes): * theme/60-inputs.css — absorbed whole, in-layer, or it loses to a theme rule by layer. */ .cbi-dynlist { height: auto; display: inline-flex; flex-direction: column; } /* item paint: theme/60-inputs.css — absorbed. Left: drag-and-drop machinery (UIDynamicList). */ .cbi-dynlist > .item { padding-block: var(--fs-space-1); padding-inline: var(--fs-space-2) 2em; position: relative; pointer-events: auto; overflow: hidden; word-break: break-all; cursor: move; user-select: text; } /* plate paint: theme/60-inputs.css — absorbed. Left: pins the × to the chip. */ .cbi-dynlist > .item::after { content: "×"; position: absolute; align-items: center; inset-block: -1px; inset-inline-end: -1px; font-weight: var(--fs-weight-bold); pointer-events: auto; } /* drop indicator (.drag-over): theme/60-inputs.css — a base rule lost to the theme border shorthands by layer */ .cbi-dynlist > .item.dragging { opacity: .5; } .cbi-dynlist > .item > span { pointer-events: none; } .cbi-dynlist > .add-item { display: flex; } .cbi-dynlist > .add-item > input, .cbi-dynlist > .add-item > button { /* flex: theme/60-inputs.css — absorbed */ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .cbi-value-field > .cbi-checkbox, .cbi-value-field > div > .cbi-radio { height: var(--fs-control-h); /* lines a toggle up with the field above it */ display: inline-flex; align-items: center; } .cbi-radio { cursor: pointer; gap: var(--fs-space-1); } /* .cbi-select and the checkbox/radio drawing: theme/60-inputs.css — absorbed whole. Do not * re-add an option rule here either: layer beats specificity, so theme's bare `option` * outranks even `.cbi-select select option:checked`. */ /* --fs-placeholder, not --fs-dim: a placeholder carries the option's DEFAULT and must not read * as a value the reader typed (03-palettes.css has the numbers). */ ::placeholder { color: var(--fs-placeholder); } /* Transitions and the focus/hover ring: the theme's one ring token * (--fs-focus-ring/--fs-focus-ring-invalid). No generic glow here. */ input[disabled], button[disabled], select[disabled], textarea[disabled], .cbi-dropdown[disabled]:not(.btn):not(.cbi-button) { opacity: var(--fs-disabled-opacity); pointer-events: none; } /* readonly border fade: theme/60-inputs.css — absorbed with the generic box */ .cbi-optionals, .cbi-section-create { padding-block: 0 var(--fs-space-3); padding-inline: var(--fs-space-3) 0; } .cbi-section-create { display: inline-flex; align-items: center; gap: var(--fs-space-2); /* not a negative-margin pair — that trick predates flex gap, leaks */ } .cbi-section-create > * { flex: 1 1 auto; } /* the input's cell-filling width: theme/60-inputs.css — absorbed with the generic box */ /* .cbi-page-actions paint: theme/55-buttons.css — absorbed. .actions has no theme override, so * it stays: some luci-app-* still emits it. */ .actions { background: var(--fs-panel2); margin-bottom: var(--fs-space-4); padding: var(--fs-card-pad); /* a plate, so it takes the card's own gutter on every side */ border-top: var(--fs-hairline); border-radius: 0 0 var(--fs-radius-lg) var(--fs-radius-lg); text-align: end; } /* Physical, hand-mirrored: docs/css.md "Widgets: .actions .secondary-action still floats, and * needs a hand RTL mirror". */ .actions .secondary-action { float: right; } :root[dir="rtl"] .actions .secondary-action { float: left; } .actions .secondary-action a, .cbi-page-actions .secondary-action a { line-height: var(--fs-control-h); } }