CSS Styles

Global Stylesheet

For reference, here is the full stylesheet used by Jhana UI. Some components have their own internal styling, but most of it is defined here. Ideally, at some point these classes will be properly documented.

@leon8ix/jhana-ui/style.css

/* > RESET */

* {
	padding: 0;
}
*:not(dialog) {
	margin: 0;
}
*,
*::before,
*::after {
	box-sizing: border-box;
}
h1,
h2,
h3,
h4,
h5,
h6 {
	font-size: inherit;
	font-weight: inherit;
}
input,
textarea,
select,
button {
	font: inherit;
}
a {
	color: inherit;
	text-decoration: none;
}
input,
textarea,
select,
button,
dialog,
[popover] {
	color: inherit;
	background-color: transparent;
	border: none;
}
fieldset,
iframe,
fencedframe {
	border: none;
}
ol,
ul,
menu,
summary {
	list-style: none;
}

/* > GLOBAL */

.theme-root {
	--tFunc: cubic-bezier(0.27, 0.17, 0.2, 1);
	--timeSm: 0.2s;
	--trans: var(--timeSm) var(--tFunc);
	--borderWidth: 1px;
	--borderWidthActive: 3px;
	--rad: 1em;
	--radLg: 1.4em;
	--inputHeight: 2.7em;
	--lineHeight: 1.5em;
	--sideSpace: 0.9em;
	--hrSideSpace: 0.3em;
	--sliderHeight: 1em;
	--sliderWidth: 2em;
	color: var(--cLight);
	background-color: var(--cDark);
	line-height: var(--lineHeight);
	user-select: none;
}
[class^='theme-'],
[class*=' theme-'] {
	--cAcc: color(display-p3 0 0.43 0.89);
	--cDark: color(display-p3 0.11 0.11 0.13);
	--cLight: color(display-p3 0.54 0.56 0.68);
	--cErr: color(display-p3 1 0 0.33);
	--cDL05: color-mix(in display-p3, var(--cDark), var(--cLight) 5%);
	--cDL10: color-mix(in display-p3, var(--cDark), var(--cLight) 10%);
	--cDL20: color-mix(in display-p3, var(--cDark), var(--cLight) 20%);
	--cDL30: color-mix(in display-p3, var(--cDark), var(--cLight) 30%);
	--cDL40: color-mix(in display-p3, var(--cDark), var(--cLight) 40%);
	--cLighter: color-mix(in display-p3, var(--cLight), white 50%);
	--cDarker: color-mix(in display-p3, var(--cDark), black 30%);
	--cAD40: color-mix(in display-p3, var(--cAcc), var(--cDark) 40%);
}

/* > TYPE */

.theme-root {
	font-family: var(--font, ui-sans-serif), ui-sans-serif, sans-serif;
	font-weight: 500;
	font-optical-sizing: auto;
	font-variation-settings: var(--fontVari);
	font-feature-settings: var(--fontFeat);
}
.monospace,
pre,
code,
kbd,
samp,
var {
	font-family: var(--fontMono, ui-monospace), ui-monospace, monospace;
	font-variation-settings: var(--fontMonoVari);
	font-feature-settings: var(--fontMonoFeat);
}
.h1 {
	font-size: 2em;
	font-weight: 750;
}
.h2 {
	font-size: 1.6em;
	font-weight: 650;
}
.h3 {
	font-size: 1.4em;
	font-weight: 600;
}
.h4 {
	font-size: 1.2em;
	font-weight: 600;
}
.h5 {
	font-size: 1em;
	font-weight: 600;
}
.numbers {
	font-variant-numeric: tabular-nums;
}
.italic {
	font-style: italic;
}
.underline {
	text-decoration: underline;
}
.text-center {
	text-align: center;
}
.text-right {
	text-align: end;
	text-align-last: end;
}
.break-all {
	word-break: break-all;
}
.link {
	text-decoration: underline;
	cursor: pointer;
	&:hover,
	&:focus-visible {
		color: var(--cLighter);
		outline: none;
	}
}
.bold,
b,
strong {
	font-weight: 700;
}
.highlight {
	font-weight: 600;
	text-decoration: underline;
}
.selectable {
	user-select: text;
	cursor: text;
}
::selection {
	background-color: var(--cLight);
	color: var(--cDark);
}
::-moz-selection {
	background-color: var(--cLight);
	color: var(--cDark);
}
kbd {
	font-size: 0.9em;
	font-weight: 600;
	padding: 0.05em 0.4em 0.15em;
	border-radius: 0.5em;
	background-color: color-mix(in display-p3, transparent, var(--cLight) 5%);
	border: solid 1px color-mix(in display-p3, transparent, var(--cLight) 20%);
}

/* > LAYOUT */

.vrt-flex {
	display: flex;
	flex-direction: column;
	align-items: stretch;

	& > .ignore > main,
	& > .vrt-fill {
		flex: 1;
		height: -webkit-fill-available;
		width: 100%;
		align-self: center;
	}
	& > .ignore > *:not(main),
	& > *:not(.vrt-fill) {
		flex-shrink: 0;
		flex-grow: 0;
	}
	& > .vrt-fill.scroll {
		overflow-y: auto;
	}
}
.block {
	display: block;
}
.rel {
	position: relative;
}
.w-full {
	width: 100%;
}
.h-full {
	height: 100%;
}
.space-y-sm > *:not(:last-child) {
	margin-bottom: 0.5em;
}
.space-y-md > *:not(:last-child) {
	margin-bottom: 1em;
}
.center-nav,
.center-nav > *:first-child,
.center-nav > *:last-child {
	display: flex;
	flex-direction: row;
	align-items: center;
	gap: 1em;
	flex: 1;
}
.center-nav > *:last-child {
	justify-content: flex-end;
}
.flex-hrz {
	display: flex;
	align-items: center;
	gap: 1em;
}
.flex-1 {
	flex: 1;
}
.icon-flex {
	display: flex;
	gap: 1em;
	align-items: center;
}
.icon-flex > *:last:child {
	flex: 1;
}
.w-sm {
	width: 6em;
}
.w-md {
	width: 7em;
}

/* > UI */

/* >> General */

.hidden,
[hidden] {
	display: none !important;
}
.disabled,
:disabled {
	opacity: 0.5;
	cursor: unset;
}
.o70 {
	opacity: 70%;
}
.o80 {
	opacity: 80%;
}
.text-err {
	color: var(--cErr);
}
hr {
	border-bottom: solid 1px var(--cLight);
	width: calc(100% - 2 * var(--hrSideSpace));
	margin-left: var(--hrSideSpace);
	margin-right: var(--hrSideSpace);
	opacity: 0.2;
}

/* >> Cards */

.card {
	/* display: block; */
	/* width: 100%; */
	padding: 1em;
	border-radius: var(--rad);
	transition:
		color var(--trans),
		border var(--trans),
		box-shadow var(--trans);

	&:not(.primary) {
		background-color: var(--cDL05);
		border: solid var(--borderWidth) var(--cDL20);
		box-shadow: 0 3px 14px rgba(0 0 0 / 0.14);

		&:not(.nohover):hover,
		&:not(.nohover):focus-visible {
			color: var(--cLighter);
			background-color: var(--cDL10);
			box-shadow: 0 5px 18px rgba(0 0 0 / 0.22);
			border-color: var(--cDL40);
			outline: none;
		}
	}

	&.primary {
		color: color-mix(in display-p3, var(--cAcc), var(--cDark) 94%);
		background-color: color-mix(in display-p3, var(--cAcc), var(--cDark) 10%);
		border: solid 3px var(--cAD40);
		box-shadow: 0 0 16px -12px var(--cAcc);

		&:not(.nohover):hover,
		&:not(.nohover):focus-visible {
			box-shadow: 0 0 22px -8px var(--cAcc);
			outline: none;
		}
	}
}
.drag-area.card {
	min-height: 10em;
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: center;
	gap: 0.3em;
	border: dashed 2px var(--cDL30);

	&:hover {
		border: dashed 2px var(--cDL40);
	}
	&.drag-over {
		border-color: var(--cAcc);
		opacity: 0.9;
	}
}
.note {
	display: block;
	width: 100%;
	padding: 1em;
	background-color: var(--cDL05);
	border-radius: var(--rad);
	border: solid var(--borderWidth) var(--cDL20);
	opacity: 0.9;
	font-style: italic;
}

/* >> Buttons */

.btn {
	padding: 0.5em 1.1em;
	border-radius: 10em;
	font-weight: 750;
	white-space: nowrap;
	transition: box-shadow var(--trans);
	line-height: normal;

	&:not(.primary) {
		background-color: var(--cLight);
		color: var(--cDark);

		&:hover:not(:disabled),
		&:focus-visible {
			box-shadow: 0 0 22px -8px var(--cLight);
		}
		&:active,
		&:focus-visible {
			outline: solid var(--borderWidthActive) var(--cDL40);
			outline-offset: calc(-1 * var(--borderWidthActive));
		}
	}
	&.primary {
		background-color: var(--cAcc);
		color: var(--cDark);

		&:hover:not(:disabled),
		&:focus-visible {
			box-shadow: 0 0 22px -8px var(--cAcc);
		}
		&:active,
		&:focus-visible {
			outline: solid var(--borderWidthActive) var(--cAD40);
			outline-offset: calc(-1 * var(--borderWidthActive));
		}
	}
	&:not(:disabled) {
		cursor: pointer;
	}
	&[type='submit'] {
		text-transform: uppercase;
	}
	&.box-btn {
		border-radius: var(--rad);
	}
	&:not(.icon):has(> img, > svg) {
		display: flex;
		align-items: center;
		gap: 0.5em;

		& > img,
		& > svg {
			margin-left: -0.1em;
			margin-right: -0.1em;
		}
	}
	&.icon {
		padding: 0.6em;

		& img,
		& svg {
			display: block;
		}
	}
}
.btn-input {
	position: relative;
	& .btn {
		--btnPad: 7px;
		position: absolute;
		top: calc(var(--btnPad) + var(--borderWidth));
		right: var(--btnPad);
		height: calc(var(--inputHeight) - 2 * var(--btnPad));
		line-height: 0.4;
		&:not(:disabled):not(:hover) {
			opacity: 0.8;
		}
	}
}
.btn-group {
	display: flex;
	gap: 0.6em;
	flex-wrap: wrap;

	&.end {
		justify-content: flex-end;
	}
}
.ctrl-group {
	background-color: var(--cDL05);
	border-radius: var(--rad);
	border: solid var(--borderWidth) var(--cDL20);
	padding: 0.5em 1em 0.5em 0.8em;
	height: 100%;
	display: flex;
	gap: 1.1em;
	align-items: center;
	flex-wrap: nowrap;

	& .btn {
		line-height: 0.7;
		margin-right: -8px;
	}
}

/* >> Tabs */

.tabs {
	display: flex;
	gap: 1.2em 0.3em;

	&.wrap {
		flex-wrap: wrap;
	}
}
.tab.btn {
	display: block;
	padding: 0.4em 0.9em 0.5em;
	border-radius: 0.2em 0.2em var(--rad) var(--rad);
	-webkit-user-drag: none;

	&:not(.primary) {
		color: var(--cLight);
		background-color: var(--cDL10);
		border: solid var(--borderWidth) var(--cDL10);

		&:hover {
			background-color: var(--cDL20);
			color: var(--cLighter);
			border-color: var(--cDL40);
		}
	}
	&.primary {
		background-color: var(--cAcc);
		color: var(--cDark);
		border: solid var(--borderWidth) var(--cAcc);
	}
}

/* >> Inputs */

.input.primary,
*:has(> .input.primary) {
	--inputHeight: 3.3em;
}
.input {
	padding: calc(0.5 * (var(--inputHeight) - var(--lineHeight))) 1em;
	line-height: var(--lineHeight);
	width: 100%;
	background-color: var(--cDL05);
	border-radius: var(--rad);
	border: solid var(--borderWidth) var(--cDL20);
	white-space: nowrap;
	transition: all var(--trans);

	&::placeholder {
		color: var(--cLight);
		opacity: 0.7;
		font-size: inherit;
	}
	&:hover,
	&:focus {
		color: var(--cLighter);
		border-color: var(--cDL40);
		box-shadow: 0 0 20px -10px var(--cLight);
	}
	&:focus {
		background-color: var(--cDarker);
		outline: none;
	}
}

/* >>> Labeled */

label:has(> .input) {
	& > span {
		display: block;
	}
	& > *:not(:last-child) {
		margin-bottom: 0.4em;
	}
	& > *:not(.input) {
		margin-left: 0.2em;
	}
}
.input-group {
	/* <fieldset> */
	display: flex;
	gap: 0.4em 1em;
	flex-wrap: wrap;

	&.vrt {
		flex-direction: column;
	}
	&:not(.vrt) {
		align-items: center;
	}
	& > legend {
		margin-left: 0.15em;
		margin-bottom: 0.4em;
	}
}

/* >>> Custom Radio/Toggle */

.radio,
.toggle {
	display: flex;
	align-items: center;
	gap: 0.6em;
	cursor: pointer;
	transition-property: color;
	transition-duration: var(--timeSm);
	transition-timing-function: var(--tFunc);

	& * {
		transition-duration: inherit;
		transition-timing-function: inherit;
	}
	& .track {
		display: inline-block;
		width: var(--sliderWidth);
		height: var(--sliderHeight);
		line-height: 1;
		border-radius: var(--sliderHeight);
		background-color: var(--cDL20);
		border: 2px solid var(--cDL30);
		box-sizing: content-box;
		transition-property: box-shadow, border-color;
	}
	& .knob {
		display: inline-block;
		width: var(--sliderHeight);
		height: var(--sliderHeight);
		border-radius: var(--sliderHeight);
	}
	&:hover input:not(:disabled),
	& input:focus-visible:not(:disabled) {
		outline: none;

		& + .track {
			box-shadow: 0 0 14px -4px var(--cLight);
			border-color: var(--cDL40);
		}
		& ~ * {
			color: var(--cLighter);
		}
	}
	& input:checked + .track > .knob {
		background-color: var(--cAcc);
		box-shadow: 0 0 14px -4px var(--cAcc);
		transition-property: scale, background-color, box-shadow;
	}
	&:has(> input:disabled) {
		cursor: unset;
		opacity: 0.7;
	}
	&:has(> input + svg) {
		align-self: stretch;
		display: flex;
		align-items: flex-end;
		margin: 0 -1em;
		transition: opacity 0.3s ease;
		padding: var(--borderWidth) 0.5em;

		& > svg {
			height: var(--inputHeight);
		}
	}
}
.radio {
	--sliderWidth: var(--sliderHeight);
	& .knob {
		background-color: var(--cDL10);
		scale: 0.4;
	}
	& input:checked + .track > .knob {
		scale: 1;
	}
}
.toggle {
	& .knob {
		background-color: var(--cLight);
		animation-duration: var(--timeSm);
		animation-fill-mode: both;
		animation-timing-function: var(--tFunc);
	}
	& input:checked + .track > .knob {
		animation-name: toggleSlideOn;
	}
	& input:not(:checked) + .track > .knob {
		animation-name: toggleSlideOff;
	}
}
@keyframes toggleSlideOn {
	50% {
		scale: 0.9 0.8;
	}
	100% {
		translate: calc(var(--sliderWidth) - var(--sliderHeight));
	}
}
@keyframes toggleSlideOff {
	0% {
		translate: calc(var(--sliderWidth) - var(--sliderHeight));
	}
	50% {
		scale: 0.95 0.8;
	}
}

/* >>> Browser */

input:autofill {
	color: var(--cLight) !important;
	-webkit-text-fill-color: var(--cLight) !important;
	background-color: transparent !important;
}
input:-webkit-autofill {
	color: var(--cLight) !important;
	-webkit-text-fill-color: var(--cLight) !important;
	background-color: transparent !important;
}
input:-webkit-autofill,
input:-webkit-autofill:focus,
input:-webkit-autofill:hover,
input:-webkit-autofill:active {
	-webkit-transition-delay: 99999s;
}
input[type='file'] {
	display: none !important;
}
input[type='radio'],
input[type='checkbox'] {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	border: 0;
	clip: rect(0, 0, 0, 0);
	overflow: hidden;
	white-space: nowrap;
}

/* >> Dialog */

dialog {
	user-select: none;
}
.dialog {
	padding: 1em;
	border-radius: 1.8em;
	background-color: var(--cDark);
	border: solid var(--borderWidth) var(--cDL20);
	box-shadow:
		0 16px 40px rgb(0 0 0 / 25%),
		0 4px 16px rgb(0 0 0 / 15%);
	&.full {
		height: 90vh;
		width: 50em;
	}
	&[open] {
		animation: open var(--trans);
	}
}
@keyframes open {
	from {
		opacity: 0;
		transform: scale(0.94);
	}
	to {
		opacity: 1;
		transform: scale(1);
	}
}

/* >> Action-List (ContextMenu & ComboBox) */

.action-list {
	overflow-y: auto;
	padding: 0.2em 0.2em;

	& > li {
		width: 100%;

		& > hr {
			margin-top: 0.2em;
			margin-bottom: 0.2em;
			border-top: none;
			border-left: none;
			border-right: none;
		}
		& > .h5 {
			padding: 0.5em 0.8em;
		}
	}
	& .action-item,
	&.all-li > li,
	&.all-button > li > button {
		padding: 0.5em 1em 0.5em 0.8em;
		border-radius: 0.8em;
		cursor: pointer;
		text-align: left;

		&:hover,
		&:focus-visible,
		&.focus {
			color: var(--cLighter);
			background-color: var(--cDL10);
			outline: solid 1px var(--cDL20);
			outline-offset: -0.5px;
		}
		&:active {
			transition: background-color var(--trans);
			background-color: var(--cDarker);
		}
	}
	&.all-button > li {
		display: flex;
		gap: 0.2em;

		& > :first-child {
			flex: 1;
		}
	}
}

/* >> Scroll Bars */

:root {
	scrollbar-color: #898fb040 transparent;
}