node-red-contrib-uibuilder
Version:
Easily create data-driven web UI's for Node-RED. Single- & Multi-page. Multiple UI's. Work with existing web development workflows or mix and match with no-code/low-code features.
1,382 lines (1,274 loc) • 38.6 kB
CSS
/** Default Styles for uibuilder - Light & Dark options ...
*
* TODO: Add darker/lighter shades for variant colours for headers, etc.
* Remove shadows for dark mode.
*
* 1em ~= 16px
* Recommended @media breakpoints:
* Tablet: 48em @ 16pt = 768px
* Tablet Wide: 62em @ 16pt = 992px
*
* Mobile Small: 30em @ 16pt = 480px
* Mobile Medium: 37.5em @ 16pt = 600px
* Mobile Large: 48em @ 16pt = 768px
*
* https://css-tricks.com/a-complete-guide-to-custom-properties/ for details on using custom css properties
* https://una.im/css-color-theming/ for more on color theory calculations
* https://web.dev/building-a-color-scheme/ is the basis for this style
* https://unifyned.com/colors.html extends the above
* https://chromatichq.com/insights/understanding-and-using-hsl-your-css gives calculations for the color wheel
*
* NB: The version is updated automatically by the build process to the current date - see gulpfile.js
* @version: 2026-06-12
* @author: Julian Knight (TotallyInformation)
* @license: Apache 2.0
* @created: 2022-05-02
*
* USAGE:
* - https://totallyinformation.github.io/node-red-contrib-uibuilder/#/client-docs/uib-brand-css
* - Reference directly or via import in own CSS
* - Will auto pick up browser preference for light/dark if set
* - Or manually set with `class="light"` or `class="dark"` on the html tag
* - Or create a manual switcher feature - see css-test.html or brand-test.html for examples
* - A simple CSS reset is provided to get reasonably looking HTML in any browser
* - Some special classes are provided - see the "Recommended surfaces" section
* - Lots of css variables provided for use in your own CSS or in web components
* NOTES:
* - Watch out for the order of loading of style sheets!
* - uibuilder attempts to auto-load this sheet BUT you may need to do it manually to get the right order.
* - Include in your index.css file as `@import url("./uib-brand.min.css");`
*/
/* :root applies to everything, :root.light is for manually selected light mode */
:root, :root.light {
color-scheme: light dark;
--mode: light;
/* Create a checkable var - helps web components know if this stylesheet is loaded
* Use this from general code:
* window.getComputedStyle(document.documentElement, null).getPropertyValue('--uib-css') === 'uib-brand'
* Or this from within the component code:
* window.getComputedStyle(this, null).getPropertyValue('--uib-css') === 'uib-brand'
* NOTE: no space between : and text!
*/
--uib-css: uib-brand;
/* For nicer emoji's use this as the font-family */
--emoji-fonts: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", "Twemoji Mozilla", "EmojiOne Color", "Android Emoji";
/* Sans-serif is much easier to read on-screen */
/* Update 2025-04-28 to use https://github.com/system-fonts/modern-font-stacks - incl better emoji's as well */
--font-family: system-ui, sans-serif, var(--emoji-fonts);
--code-font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace, var(--emoji-fonts);
--cursive-font-family: 'Segoe Print', 'Bradley Hand', Chilanka, TSCu_Comic, casual, cursive, var(--emoji-fonts);
--base-margin: 1rem;
--max-width: 64rem;
--border-radius: 0.5rem; /*8px;*/
--border-pad: 0.5rem;
--border-margin: 0;
/* For the .grid-fit class, the minimum child element size */
--grid-fit-min: 15rem;
/* For the show/hide elements in PWA mode */
--pwa-display-mode: block;
/* #region Fix link colours when using dark mode in a light mode browser and visa versa */
--a-link: blue;
--a-visited: purple;
--a-hover: red; /* Hover state (must be after link/visited) Hover doesn't seem to be defined in Chromium */
--a-active: orange; /* Active state (must be after hover) This is when you hold mouse down on the link */
/* #endregion --- Fix link colours --- */
/* #region --- Colour Prep --- */
--brand-hue: 200;
--text-hue: var(--brand-hue);
--surface-hue: var(--brand-hue);
--complementary-offset: 180;
--accent-offset: 30; /* 30=Split complementary, 60=Triadic */
--saturation-bias: 0;
--light-saturation: .66;
--dark-saturation: calc(var(--light-saturation) * .6);
--saturation-value: var(--light-saturation);
--saturation: calc(var(--saturation-value) + var(--saturation-bias));
--lightness-bias: 0;
--light-lightness: .57;
--dark-lightness: calc(var(--light-lightness) * .75);
--lightness-value: var(--light-lightness);
--lightness: calc(var(--lightness-value) + var(--lightness-bias));
/* #endregion --- Colour Prep --- */
/* #region --- Brand --- */
--brand: hsl(
var(--brand-hue)
calc(100% * var(--saturation))
calc(100% * var(--lightness))
);
/*#endregion --- Brand --- */
/* #region --- Shadows https://shadows.brumm.af/ --- */
--surface-shadow-light: var(--brand-hue) 10% 20%;
--shadow-strength-light: .02;
--surface-shadow-dark: var(--brand-hue) 30% 30%;
--shadow-strength-dark: .1;
--surface-shadow: var(--surface-shadow-light);
--shadow-strength: var(--shadow-strength-light);
--shadow1:
0 2.8px 2.2px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .03)),
0 6.7px 5.3px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .01)),
0 12.5px 10px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .02)),
0 22.3px 17.9px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .02)),
0 41.8px 33.4px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .03)),
0 100px 80px hsl(var(--surface-shadow) / var(--shadow-strength))
;
--shadow2:
0.2px 0.3px 0.3px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .031)),
0.5px 0.7px 0.7px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .053)),
1px 1.3px 1.3px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .07)),
1.8px 2.2px 2.2px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .087)),
3.3px 4.2px 4.2px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .109)),
8px 10px 10px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .16))
;
--shadow: var(--shadow1);
--btn-shadow: inset 2px 2px 3px rgba(255,255,255, .3),
inset -2px -2px 3px rgba(0,0,0, .3);
/*#endregion --- --- */
/* #region --- Text --- */
--text-saturation: .2;
--text-bias: 0;
--light-text-lightness: .1;
--light-text-factor: 1;
--dark-text-lightness: .9;
--dark-text-factor: -1;
--text-factor: var(--light-text-factor);
--text-lightness: var(--light-text-lightness);
--text1: hsl(
var(--text-hue)
calc(100% * var(--text-saturation))
calc(
100% * (var(--text-lightness)
- (var(--text-factor) * var(--text-bias)))
)
);
--text2: hsl(
var(--text-hue)
calc(100% * (var(--text-saturation) / 2))
calc(
100% * (var(--text-lightness)
+ (1 * var(--text-factor) * .1)
- (var(--text-factor) * var(--text-bias)))
)
);
--text3: hsl(
var(--text-hue)
calc(100% * (var(--text-saturation) / 2))
calc(
100% * (var(--text-lightness)
+ (1 * var(--text-factor) * .4)
- (var(--text-factor) * var(--text-bias)))
)
);
--text4: hsl(
var(--text-hue)
10%
calc(
50%
- (100% * var(--text-factor) * var(--text-bias)))
/ calc(25% + (100% * var(--text-bias)))
);
/*#endregion --- --- */
/* #region --- Surfaces --- */
--surfaces-saturation: .1;
--surfaces-bias: 0;
--light-surfaces-lightness: .95;
--light-surfaces-factor: 1;
--dark-surfaces-lightness: .1;
--dark-surfaces-factor: -1;
--surfaces-factor: var(--light-surfaces-factor);
--surfaces-lightness: var(--light-surfaces-lightness);
--surface1: hsl(
var(--surface-hue)
calc(100% * var(--surfaces-saturation))
calc(
100% * (var(--surfaces-lightness)
- (var(--surfaces-factor) * .00)
+ (var(--surfaces-factor) * var(--surfaces-bias)))
)
);
--surface2: hsl(
var(--surface-hue)
calc(100% * var(--surfaces-saturation))
calc(
100% * (var(--surfaces-lightness)
- (var(--surfaces-factor) * .05)
+ (var(--surfaces-factor) * var(--surfaces-bias)))
)
);
--surface3: hsl(
var(--surface-hue)
calc(100% * var(--surfaces-saturation))
calc(
100% * (var(--surfaces-lightness)
- (var(--surfaces-factor) * .10)
+ (var(--surfaces-factor) * var(--surfaces-bias)))
)
);
--surface4: hsl(
var(--surface-hue)
calc(100% * var(--surfaces-saturation))
calc(
100% * (var(--surfaces-lightness)
- (var(--surfaces-factor) * .15)
+ (var(--surfaces-factor) * var(--surfaces-bias)))
)
);
--surface5: hsl(
var(--surface-hue)
calc(100% * var(--surfaces-saturation))
calc(
100% * (var(--surfaces-lightness)
- (var(--surfaces-factor) * .20)
+ (var(--surfaces-factor) * var(--surfaces-bias)))
)
);
/*#endregion --- --- */
/* #region === INFO === */
--info-hue: 203;
--info-saturation-bias: 0;
--info-lightness-bias: 0;
--info-hsl: var(--info-hue)
calc(100% * (var(--saturation) + var(--info-saturation-bias)))
calc(100% * (var(--lightness) + var(--info-lightness-bias)));
--info: hsl( var(--info-hsl) );
--info-intense: hsl(
var(--info-hue) 100% 50%
);
/*#endregion --- --- */
/* #region === SUCCESS === */
--success-hue: 120;
--success-saturation-bias: 0;
--success-lightness-bias: 0;
--success: hsl(
var(--success-hue)
calc(100% * (var(--saturation) + var(--success-saturation-bias)))
calc(100% * (var(--lightness) + var(--success-lightness-bias)))
);
--success-intense: hsl(
var(--success-hue) 100% 50%
);
/*#endregion --- --- */
/* #region === WARNING === */
--warning-hue: 40;
--warning-saturation-bias: 0;
--warning-lightness-bias: 0;
--warning: hsl(
var(--warning-hue)
calc(100% * (var(--saturation) + var(--warning-saturation-bias)))
calc(100% * (var(--lightness) + var(--warning-lightness-bias)))
);
--warning-intense: hsl(
var(--warning-hue) 100% 50%
);
--warn: var(--warning);
/*#endregion --- --- */
/* #region === FAILURE === */
--failure-hue: 2;
--failure-saturation-bias: 0;
--failure-lightness-bias: 0;
--failure: hsl(
var(--failure-hue)
calc(100% * (var(--saturation) + var(--failure-saturation-bias)))
calc(100% * (var(--lightness) + var(--failure-lightness-bias)))
);
--failure-intense: hsl(
var(--failure-hue) 100% 50%
);
--error: var(--failure);
--danger: var(--failure);
/*#endregion --- --- */
/* #region === Complementary ACCENT === */
--complementary-hue: calc(var(--brand-hue) + var(--complementary-offset));
--complementary-fg: hsl(
var(--brand-hue)
calc(100% * var(--saturation))
calc(100% * var(--lightness))
);
--complementary-bg: hsl(
var(--complementary-hue)
calc(100% * var(--saturation))
calc(100% * var(--lightness))
);
--complementary: hsl(
calc(var(--complementary-hue))
calc(100% * var(--saturation))
calc(100% * var(--lightness))
);
/*#endregion --- --- */
/* #region === PRIMARY ACCENT === */
--primary-hue: calc(var(--brand-hue) + var(--complementary-offset) + var(--accent-offset));
--primary-fg: hsl(
calc(var(--primary-hue) + var(--complementary-offset))
calc(100% * var(--saturation))
calc(100% * var(--lightness))
);
--primary-bg: hsl(
var(--primary-hue)
calc(100% * var(--saturation))
calc(100% * var(--lightness))
);
--primary: var(--primary-bg);
/*#endregion --- --- */
/* #region === SECONDARY ACCENT === */
--secondary-hue: calc(var(--brand-hue) + var(--complementary-offset) - var(--accent-offset));
--secondary-fg: hsl(
calc(var(--secondary-hue) + var(--complementary-offset))
calc(100% * var(--saturation))
calc(100% * var(--lightness))
);
--secondary-bg: hsl(
var(--secondary-hue)
calc(100% * var(--saturation))
calc(100% * var(--lightness))
);
--secondary: var(--secondary-bg);
/*#endregion --- --- */
/* #region === FORMS === */
--form-bg: var(--surface2);
--form-fg: var(--text2);
--form-border: 1px solid var(--text3);
/* #endregion --- --- */
/* #region ---- Z-Indexes (since 2026-03-16 uib v7.6.0) ---- */
--z-nav-h: 980; /* Horizontal navigation menu */
--z-toaster: 992; /* Toast container */
--z-toast: 990; /* Individual toast - inside toaster only if modal */
--z-info-overlay: 10000; /* For info overlays that need to be above everything else */
/* #endregion ---- Z-Indexes ---- */
/* #region === NAVIGATION MENUS === */
/* The main background color for the menu */
--nav-bg: var(--surface3);
/* The main text color for the menu */
--nav-fg: var(--text2);
/* Secondary background color - used when hovering over other menu items */
--nav-2nd-bg: var(--primary-bg);
/* More contrasting text color - used for selected menu items */
--nav-2nd-fg: var(--text1);
/* More contrasting background color - Used for menu pop-up background */
--nav-3rd-bg: var(--surface2);
/* #endregion --- --- */
}
/* If the browser reports it, we can adjust for light/dark theme preferences
* See https://stackoverflow.com/a/57795495 for use with JavaScript
*/
@media (prefers-color-scheme: light) {
:root {
color-scheme: light dark;
--mode: light;
}
}
@media (prefers-color-scheme: dark) {
:root {
/* ---- Active Theme (Dark) ---- */
color-scheme: dark light;
--mode: dark;
--saturation-value: var(--dark-saturation);
--lightness-value: var(--dark-lightness);
--surface-shadow: var(--surface-shadow-dark);
--shadow-strength: var(--shadow-strength-dark);
--text-factor: var(--dark-text-factor);
--text-lightness: var(--dark-text-lightness);
--surfaces-factor: var(--dark-surfaces-factor);
--surfaces-lightness: var(--dark-surfaces-lightness);
}
}
/* Or if the user manually requests a dark colour theme by setting class="dark" on html tag */
:root.dark {
color-scheme: dark light;
--mode: dark;
--saturation-value: var(--dark-saturation);
--lightness-value: var(--dark-lightness);
--surface-shadow: var(--surface-shadow-dark);
--shadow-strength: var(--shadow-strength-dark);
--text-factor: var(--dark-text-factor);
--text-lightness: var(--dark-text-lightness);
--surfaces-factor: var(--dark-surfaces-factor);
--surfaces-lightness: var(--dark-surfaces-lightness);
/* #region Fix link colours when using dark mode in a light mode browser and visa versa */
--a-link: hsl(240, 100%, 81%);
--a-visited: hsl(271, 69%, 81%);
--a-hover: hsl(0, 100%, 70%); /* Hover state (must be after link/visited) Hover doesn't seem to be defined in Chromium */
--a-active: hsl(30, 100%, 50%); /* Active state (must be after hover) This is when you hold mouse down on the link */
/* #endregion --- Fix link colours --- */
}
/*#region --- Surface & std colour classes --- */
.brand {
color: var(--text1);
background-color: var(--brand);
}
.complementary {
color: var(--text1);
background-color: var(--complementary);
}
.surface1 {
background-color: var(--surface1);
color: var(--text2);
}
.surface2 {
background-color: var(--surface2);
color: var(--text2);
}
.surface3 {
background-color: var(--surface3);
color: var(--text1);
}
.surface4 {
background-color: var(--surface4);
color: var(--text1);
}
.surface5 {
background-color: var(--surface5);
color: var(--text1);
}
.rad-shadow {
box-shadow: var(--shadow);
}
.info {
color: var(--text1) ;
background-color: var(--info) ;
}
.info-intense {
color: var(--text1) ;
background-color: var(--info-intense) ;
}
.success {
color: var(--text1) ;
background-color: var(--success) ;
}
.success-intense {
color: var(--text1) ;
background-color: var(--success-intense) ;
}
.warning, .warn {
color: var(--text1) ;
background-color: var(--warning) ;
}
.warning-intense, .warn-intense {
color: var(--text1) ;
background-color: var(--warning-intense) ;
}
.failure, .error, .danger {
color: var(--text1) ;
background-color: var(--failure) ;
}
.failure-intense, .error-intense, .danger-intense {
color: var(--text1) ;
background-color: var(--failure-intense) ;
}
.primary {
color: var(--primary-fg);
background-color: var(--primary-bg);
}
.secondary {
color: var(--secondary-fg);
background-color: var(--secondary-bg);
}
/*#endregion --- --- --- --- */
/*#region --- Basic reset --- */
*, *::before, *::after {
box-sizing: border-box;
/* margin: 0; */
}
*:focus-visible {
outline: 2px solid var(--secondary-fg);
outline-offset: 2px;
}
@supports not selector(:focus-visible) {
*:focus {
outline: 1px solid var(--secondary-fg);
outline-offset: -4px;
}
}
html {
line-height: 1.5; /* Accessible line-height */
font-size: 100%;
background-color: var(--surface1);
color: var(--text2);
accent-color: var(--primary);
}
body {
margin-left: var(--base-margin);
margin-right: var(--base-margin);
/* padding: 0.3rem; */
font-family: var(--font-family);
-webkit-font-smoothing: antialiased; /* Improve text rendering */
}
h1, h2, h3, h4, h5, h6, heading {
line-height: calc(1em + 0.5rem); /* dynamic heights for headings */
text-wrap: balance;
}
p, li, figcaption {
text-wrap: pretty;
}
img, picture, video, canvas, svg {
/* display: block; */
object-fit: cover;
vertical-align: bottom;
max-width: 100%;
background-color: var(--surface2);
margin:var(--base-margin);
}
p, h1, h2, h3, h4, h5, h6, heading, li, dl, dt, blockquote {
overflow-wrap: break-word;
-webkit-hyphens: auto;
hyphens: auto;
word-break: break-word;
}
div > p, div > article {
margin-left: var(--base-margin);
margin-right: var(--base-margin);
}
button, input[type="button" i], input[type="reset" i], input[type="submit" i], ::file-selector-button {
/* display: inline-flex; */
align-items: center;
justify-content: center;
border: none;
padding: .5rem 1rem;
text-decoration: none;
background-color: var(--info);
color: var(--text1);
font-family: inherit;
font-size: 1rem;
line-height: 1.1;
cursor: pointer;
text-align: center;
transition: background 250ms ease-in-out, transform 150ms ease;
-webkit-appearance: none;
appearance: none;
border-radius: var(--border-radius);
/* box-shadow: 0 3px 5px rgb(var(--uib-color-fg), 0.5); */
box-shadow: var(--btn-shadow);
}
button:hover, input[type="button" i]:hover, input[type="reset" i]:hover, input[type="submit" i]:hover {
background-color: hsl(var(--info-hsl) / .5);
}
button:active, input[type="button" i]:active, input[type="reset" i]:active, input[type="submit" i]:active {
transform: scale(0.97);
}
input, button, textarea, select {
color: var(--text2);
font: inherit;
min-width: 2em;
}
input, textarea {
background-color: var(--surface1);
}
select {
background-color: var(--info);
color: var(--text2);
padding: 0.3rem;
box-shadow: var(--btn-shadow);
cursor: pointer;
transition: background 250ms ease-in-out, transform 150ms ease;
border-radius: var(--border-radius);
border: none;
}
blockquote {
/* box-shadow: var(--shadow); */
padding: 0.5em 1em 0.5em 1em;
margin: 0.5em 0 1em 0;
color: inherit;
border: none;
border-left: 0.25em solid var(--text3);
background-color: var(--surface3);
box-shadow: none;
p, div {
margin: 0.3em 0;
}
}
code {
display: inline-block;
font-size: 120%;
background-color: var(--surface3);
padding: 0 0.3em 0 0.3em;
}
header, footer, main, section, article {
/* default prep for container queries */
container-type: inline-size;
}
article { /* This lets us use an article like a card display */
max-width: var(--max-width);
border: 1px solid var(--text3);
border-radius: var(--border-radius);
padding: var(--border-pad);
margin: 1rem var(--border-margin);
background-color: var(--surface3);
}
article > h1::before {
font-size: 50%;
color: hsl( var(--failure-hue) 100% 50% );
content: "⛔ Do not use H1 headings in articles. "
}
article > h2, article > h3, article > h4 {
margin-block-start: 0;
border-bottom: 1px solid var(--text3);
padding-block-end: var(--border-pad);
}
/* HTML5 section tags - only special format top-level to reduce odd fmts */
body > main, body > header, body > footer, body > section {
padding-left: var(--base-margin);
padding-right: var(--base-margin);
max-width: var(--max-width);
margin: 0 auto;
}
body > main {
display: grid;
gap: 1rem;
}
footer {
margin-top: 1em;
}
/* Put asides inside a main to one side
Or, use a section or div to wrap multiple */
main > article, main .left {
grid-column: 1;
}
main > aside, main .right {
grid-column: 2;
}
summary {
cursor: pointer;
}
/* Inline blocks in a summary tag */
summary > h2, summary > h3, summary > h4, summary > div, summary > p {
display: inline-block;
}
/* #region Fix link colours when using dark mode in a light mode browser and visa versa */
/* Default and visited states */
a:link {
color: var(--a-link, blue);
}
a:visited {
color: var(--a-visited, purple);
}
/* Hover doesn't seem to be defined in Chromium */
/* Hover state (must be after link/visited) */
a:hover {
color: var(--a-hover, red);
text-decoration-style: double;
}
/* This is when you hold mouse down on the link */
/* Active state (must be after hover) */
a:active {
color: var(--a-active, orange);
}
/* #endregion --- Fix link colours --- */
/*#endregion --- Basic reset --- */
/*#region --- Tables --- */
table {
border-collapse: collapse;
border: 1px solid var(--text3);
margin-top: 1rem;
margin-bottom: 1rem;
font-variant-numeric: tabular-nums; /* OpenType: better alignment of numbers */
}
thead th, thead td {
color: var(--text2);
font-weight: bolder;
background: var(--surface4);
/* Make table headers stick to page when scrolling */
position: -webkit-sticky;
position: sticky;
}
tfoot th, tfoot td {
color: var(--text2);
font-style: italic;
background: var(--surface4);
}
th[scope=row], tbody th {
font-style: italic;
color: var(--text2);
font-weight:lighter;
background: var(--surface4);
background-blend-mode: lighten;
text-align: left;
}
th, td {
padding: .5rem;
border: 1px solid var(--text4);
}
tbody tr:nth-child(even) {
color: var(--text2);
background-color: var(--surface3);
background-blend-mode: lighten;
}
/* In case you want to use an hr in a table, reduced top/bottom margins */
td hr {
margin-top:0.5em;
margin-bottom:0.5em;
}
/* Extra line spacing for <br> in tables, mainly for use in markdown */
td br, th br {
display:block;
content:"";
margin-top:0.8em;
line-height:190%;
}
/*#endregion --- Tables --- */
/*#region --- Forms --- */
form {
display: flex;
gap: 1em;
flex-direction: column;
background-color: var(--form-bg);
color: var(--form-fg);
border: var(--form-border);
margin: 0.5rem;
padding: 0.5rem;
border-radius: var(--border-radius);
}
input[type="color"] {
width: 100%;
height: 2.5rem;
}
input:invalid, textarea:invalid, select:invalid {
/* outline: 2px solid var(--failure); */
border: 2px solid var(--failure);
}
/* input:valid, textarea:valid, select:valid {
border: 3px solid var(--success);
} */
/* at any level of nesting */
form input, form textarea, form select, form fieldset, form output {
/* width: 75%; */
flex: 2;
border-radius: var(--border-radius);
padding:0.3rem;
border: var(--form-border);
}
form button, input[type="button" i], form input[type="reset" i], form input[type="submit" i] {
width:auto;
margin-left: .2em;
margin-right: .2em;
}
form input[type="checkbox" i], form input[type="radio" i] {
height:1.5em;
vertical-align: middle;
}
form:invalid button {
background-color: var(--warning);
}
form label {
flex: 1;
vertical-align: middle;
display: inline-block;
}
form label[required]::after {
content: " *"
}
/* first level only */
form > div {
display: inherit;
vertical-align: middle;
}
form > div:focus-within {
font-weight: bold;
}
form > label {
align-self: center;
text-transform: capitalize;
}
form > label:focus-within {
font-weight: bold;
}
/* Small screen (37.5em @ 16pt is about 600px) */
@media all and (max-width: 37.5em) {
form, form * {
display:block;
width:100%;
}
form > label, form > div.btn-row {
margin-top: .8rem;
}
form > :not(label) {
margin-bottom: 0.5rem;
}
}
/*#endregion --- Forms --- */
/*#region --- Menus --- */
nav {
/* See :root for the CSS variables used */
background-color: var(--nav-bg);
border-radius: var(--border-radius);
box-shadow: var(--surface-shadow);
}
nav ul {
list-style-type: none;
}
nav [role="menuitem"]:not([aria-current="page"]):hover {
text-decoration: underline;
color: var(--nav-2nd-fg);
background-color: var(--nav-2nd-bg);
}
nav [aria-current="page"] {
background-color: hsl( /* brand but a bit darker */
var(--brand-hue),
calc(100% * var(--saturation)),
calc(80% * var(--lightness))
);
font-weight: bolder;
color: var(--nav-2nd-fg);
}
nav a {
text-decoration: none;
color: inherit;
background-color: inherit;
}
button.menu-toggle {
/* Hide the toggle by default */
display: none;
/* display: block; */
cursor: pointer;
padding: 0;
}
button.menu-toggle svg {
width: 2em;
height: 2em;
fill: var(--nav-fg);
background-color: var(--nav-bg);
transition: transform 150ms ease-in-out;
margin:0;
padding: 0;
}
/*#region -- Horizontal menu -- */
/* nav.horizontal {
display: inline-block;
padding: 0.5rem;
} */
nav.horizontal {
display: flex;
padding: 0.5rem;
align-items: center;
/* background-color: var(--nav-bg); */
/* border-radius: var(--border-radius); */
position: relative;
}
nav.horizontal > h2 { /* Menu heading */
font-size: inherit;
font-weight: inherit;
padding-left: 0.5rem;
}
nav.horizontal ul { /* [role="menubar"] */
display: flex;
flex: 2;
list-style-type: none;
margin: 0;
padding: 0;
justify-content: flex-start;
}
nav.horizontal [role="menuitem"] {
padding: .5rem .5rem;
}
/* Search form */
nav.horizontal form {
flex: 1;
display: inline-flex;
flex-wrap: nowrap;
flex-direction: row;
align-items: center;
border: none;
margin: inherit;
padding: inherit;
gap: .2rem;
}
nav.horizontal input[type="search"] {
flex: 3;
filter: brightness(120%);
}
nav.horizontal input[type="submit"] {
flex: 1;
font-size: large;
font-weight: bolder;
filter: brightness(120%);
padding: .5rem 0;
}
@media (max-width: 600px) {
nav.horizontal ul {
display: none;
}
nav.horizontal[aria-expanded="true"] ul {
display: flex;
flex-direction: column;
position: absolute;
background: var(--nav-3rd-bg);
box-shadow: var(--shadow);
padding: 0.5em 0.5em;
border-radius: var(--border-radius);
z-index: var(--z-nav-h);
left: 1.6em;
top: 1em;
width: max-content;
min-width: 60vw;
max-width: 90vw;
}
nav.horizontal[aria-expanded="true"] a {
display: block;
width: 100%;
}
nav.horizontal > .menu-toggle {
display: inline-block;
}
}
/*#endregion -- ---- -- */
/*#endregion --- Menus --- */
/*#region --- Lists --- */
.checklist {
margin-inline-start: var(--base-margin);
margin-inline-end: var(--base-margin);
padding-inline-start: .2rem;
}
li.check, li.completed {
list-style-type: "✅";
padding-left: 0.4rem;
font-family: var(--emoji-fonts);
}
li.uncheck, li.unstarted {
list-style-type: "❌";
padding-left: 0.4rem;
font-family: var(--emoji-fonts);
}
li.started {
list-style-type: "✔️";
padding-left: 0.4rem;
font-family: var(--emoji-fonts);
}
/*#endregion --- Lists --- */
/*#region ---- Utility ---- */
.animate-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes pulse {
50% {
opacity: .5;
}
}
.border {
border: 1px solid var(--text3);
border-radius: var(--border-radius);
padding: var(--border-pad);
margin: var(--border-margin);
}
.box {
border: 1px solid var(--text3);
border-radius: var(--border-radius);
padding: 0.5rem;
}
.box h2, .box h3, .box h4, .box h5, .box h6 {
margin-top: 0.5rem;
}
.centre, .center {
margin-left:auto;
margin-right: auto;
text-align: center;
}
.compact {
margin: 0;
padding-top: 0.2rem;
padding-bottom: 0.2rem;
}
button.compact {
padding: 2px 5px;
border-radius: 0;
background: inherit;
margin: 2px;
}
.emoji { /* Nicer, cross-platform emoji's */
font-family: var(--emoji-fonts);
}
.noborder {
border: none;
}
.text-larger {
font-size: larger;
}
.text-smaller {
font-size: smaller;
}
/* Utility class to show/hide elements in PWA mode */
.show-in-pwa {
display: none ;
}
.hide-in-pwa {
display: var(--pwa-display-mode, block);
}
@media (display-mode: standalone), (display-mode: minimal-ui) {
.show-in-pwa {
display: var(--pwa-display-mode, block);
}
.hide-in-pwa {
display: none ;
}
}
/** These are useful for things like buttons.
* Default to 5em in size but are easily customised
* using CSS variables.
* @example
* <button class="square" style="--sq: 10em;">Square</button>
* <button class="round" style="--dia: 10em;">Round</button>
* <button class="square" style="--sq: 10em;--sqw: 20em;">Rectangle</button>
* <button class="round" style="--dia: 10em;--roundw: 20em;">Oval</button>
*/
/* Make something square or rectangular. */
.square {
--sq: 5em;
width: var(--sqw, var(--sq));
height: var(--sqh, var(--sq));
border-radius: calc(var(--sq) * 0.1);
}
/* Make something circular, oval or pill-shaped */
.round {
--dia: 5em;
width: var(--roundw, var(--dia));
height: var(--roundh, var(--dia));
border-radius: var(--roundb, var(--dia));
}
/* Apply to headings where you want a sub-title */
.with-subtitle {
margin-bottom: 0;
}
/* Add the subtitle as a div with the Aria role */
[role="doc-subtitle"] {
font-size: smaller;
font-style: italic;
margin-bottom: 1em;
}
.uppercase {
text-transform: uppercase;
}
/* Visually hidden but still accessible to screen readers
Use for skip links, form explanations, status updates
otherwise not needed for sighted users.
*/
.visually-hidden:not(:focus):not(:active) {
/* Tab focusable elements will be visible when active */
border: 0;
clip-path: inset(100%);
height: 1px;
margin: 0;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/*#endregion ---- Utility ---- */
/*#region -- Toasts/Notifications/Alerts - Readable pop-over notifications -- */
.toaster {
position:absolute;
top:0; left:0;
min-width:100vw; min-height:100vh;
z-index: var(--z-toaster);
-webkit-backdrop-filter: grayscale(60%) blur(10px);
backdrop-filter: grayscale(60%) blur(10px);
display:flex;
flex-direction:column;
--toast-x-position: center;
--toast-y-position: center;
align-items: var(--toast-x-position, center);
justify-content: var(--toast-y-position, center);
}
.toast { /* Individual toast - only inside toaster if modal */
background: var(--surface1);
color: var(--text2);
border: 4px solid var(--text3);
border-radius: var(--border-radius);
box-shadow: var(--shadow2);
background-clip: border-box;
box-sizing: border-box;
min-width:50vw; max-width:50vw; max-height:50vh; overflow-y:auto;
padding:1em; margin-bottom:.5em; margin-top:.5em;
z-index: var(--z-toast);
/* Allow for further positioning of the toast */
position:relative;
top:auto;left:auto;
}
/* .toast.alert {
} */
.toast-head > svg {
width: 30px;
background-color: var(--surface1);
fill: var(--warning-intense);
float: left;
margin: .5em .8em 0.5em .1em;
}
.toast-head {
font-weight: bold
}
.toast-body {
clear: both;
}
/* Old settings
.toaster {
position:absolute;
top:0; left:0; min-width:100vw; min-height:100vh;
-webkit-backdrop-filter: grayscale(60%) blur(10px);
backdrop-filter: grayscale(60%) blur(10px);
display:flex; flex-direction:column; justify-content:center; align-items:center;
z-index:998;
}
.toast {
border: 4px solid var(--text3);
border-radius: var(--border-radius);
box-shadow: var(--shadow2);
background-clip: border-box;
box-sizing: border-box;
min-width:50vw; max-width:50vw; max-height:50vh; overflow-y:auto;
padding:1em; margin-bottom:.5em; margin-top:.5em;
z-index:999;
}
.toast.alert {
border: 4px solid var(--text3);
border-radius: var(--border-radius);
box-shadow: var(--shadow2);
background-clip: border-box;
box-sizing: border-box;
min-width:50vw; max-width:50vw; max-height:50vh; overflow-y:auto;
padding:1em; margin-bottom:.5em; margin-top:.5em;
z-index:999;
}
.toast-head {font-weight:bold} */
/*#endregion -- Toasts/Notifications/Alerts - Readable pop-over notifications -- */
/*#region ---- Status Grid ---- */
.status-grid {
--status-grid-min: 14em;
--status-grid-max: 1fr;
--status-grid-gap: 0.5rem;
display:grid;
grid-template-columns: repeat(auto-fit, minmax(var(--status-grid-min), var(--status-grid-max)));
gap: var(--status-grid-gap);
list-style-position: inside;
}
.status-heading {
grid-column: 1/-1;
}
.status-link {
display:contents;
color:inherit;
text-decoration:none;
}
.status-side-panel {
border-radius: 9999px;
width: .5rem;
height: 100%;
background-color: var(--status-color, var(--surface1));
}
/*#endregion ---- ---- ---- */
/*#region ---- Flex/Grid Layouts ---- */
.grid {
display:grid;
gap:0.5rem;
}
.grid-2 {
display:grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap:0.5rem;
}
.grid-3 {
display:grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
/* grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); */
gap:0.5rem;
}
.grid-4 {
display:grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap:0.5rem;
}
.grid-fit {
display: grid;
gap: 0.5rem;
grid-template-columns: repeat(auto-fit, minmax(min(var(--grid-fit-min), 100%), 1fr));
}
.flex {
display: flex;
gap:0.5rem;
}
.flex-wrap {
display: flex;
flex-wrap: wrap;
gap:0.5rem;
}
/*#endregion ---- ---- ---- */
/*#region for Syntax Highlighted pre's */
#uib_last_msg_wrap {
position:relative;
}
#uib_last_msg_wrap > button {
display:none;
position:absolute;
color:hsl(0,0%,50%,.5);
}
#uib_last_msg_wrap:hover > button {
display:initial;
}
#uib_last_msg_wrap > button:hover {
color:hsl(0,0%,50%,1);
}
.syntax-highlight {
color:white;
display:block;
background-color:black;
padding:5px 10px;
font-family: Consolas, "ui-monospace", "Lucida Console", monospace;
font-size: smaller;
white-space: pre;
width: 99%;
height: var(--syntax-highlight-height, 22em);
overflow: auto;
resize: both;
}
.syntax-highlight > .key {color:#ffbf35}
.syntax-highlight > .string {color:#5dff39;}
.syntax-highlight > .number {color:#70aeff;}
.syntax-highlight > .boolean {color:#b993ff;}
.syntax-highlight > .null {color:#93ffe4;}
.syntax-highlight > .undefined {color:#ff93c9;}
/*#endregion */
/* #region ---- Information Overlay Panel ---- */
#uib-info-overlay {
--callout-color: var(--text2);
--callout-bgcolor: var(--surface3);
position: fixed;
top: 0;
left: 50%;
transform: translateX(-50%);
z-index: var(--z-info-overlay);
max-width: 90vw;
width: auto;
min-width: 21em;
padding: 0.5em;
background-color: var(--surface5);
border: 2px solid var(--surface5);
}
.uib-overlay-entry {
background-color: var(--callout-bgcolor);
border: 2px solid var(--callout-color);
border-radius: var(--border-radius, 0.5em);
box-shadow: 0 0 2px 2px var(--callout-color);
padding: 1em;
margin-bottom: 0.5rem;
}
.uib-overlay-header {
display: flex;
align-items: center;
gap: 0.5rem;
}
.uib-overlay-icon {
font-size: 1.2em;
}
.uib-overlay-title {
margin: 0;
color: var(--callout-color);
}
.uib-overlay-dismiss {
margin-left: auto;
background: transparent;
border: none;
font-size: 1.5em;
cursor: pointer;
padding: 0.25rem;
border-radius: 0;
box-shadow: none;
transition: background-color 0.2s;
}
.uib-overlay-dismiss:hover {
background-color: var(--surface2) ;
}
/* #endregion ---- Information Overlay Panel ---- */