wrolpi/app/src/App.css
Roland 53f9386c85 Theme: fix white corner cell on inverted definition tables.
Semantic UI paints a definition table's empty corner cell white to fake a
"cut-out" corner against a white page. Our dark theme has a dark page, so
the corner rendered as a white square. Override the background and border
box-shadows to transparent for inverted tables only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 15:27:34 -06:00

609 lines
13 KiB
CSS

.channel-edit {
border-radius: 3px;
padding: 0.75em;
}
.channel-edit:hover {
background-color: #7abaff;
cursor: pointer;
}
::-ms-clear {
display: none;
}
.form-control-clear {
z-index: 10;
pointer-events: auto;
cursor: pointer;
}
pre.wrap-text {
white-space: pre-wrap; /* Since CSS 2.1 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
.duration-overlay {
position: absolute;
top: 4px;
right: 4px;
color: black;
background: #ffffff;
padding: 0px 4px;
border-radius: 3px;
}
.no-link-underscore {
text-decoration: none !important;
}
.card-link {
color: black;
}
.center-me {
margin: 0 auto;
}
div.inverted {
background-color: #1B1C1D;
}
.toggle {
position: relative;
display: inline-block;
width: 49px;
height: 23px;
}
.toggle input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgb(166, 166, 166);
-webkit-transition: .4s;
transition: .4s;
border-radius: 34px;
}
.slider:before {
position: absolute;
content: "";
height: 22px;
width: 22px;
left: 0;
bottom: 0;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
border-radius: 50%;
}
.slider.disabled:before {
background-color: #CCCCCC;
}
input:checked + .slider {
background-color: #6435C9FF;
}
input.inverted:checked + .slider.inverted {
background-color: #6435C9AA;
}
input.disabled + .slider {
background-color: rgb(147, 147, 147);
}
input:checked + .slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
.inverted-progress-text.ui.indicating.progress .bar > .progress,
.inverted-progress-text.ui.progress > .label {
color: white !important;
}
/* Light bar colors (yellow, olive) need dark text on the bar — must override inverted-progress-text. */
.light-bar-progress-text.ui.indicating.progress .bar > .progress,
.light-bar-progress-text.ui.progress .bar > .progress {
color: rgba(0, 0, 0, 0.85) !important;
}
/* File preview Modal.Actions toolbar.
Single layout that works at every viewport — buttons keep their order at any width.
On narrow screens, the tags selector wraps to its own line while the button groups stay together. */
.preview-toolbar {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5em;
}
.preview-toolbar-group {
display: flex;
align-items: center;
gap: 0.25em;
flex: 0 0 auto;
}
.preview-toolbar-tags {
flex: 1 1 200px;
min-width: 0;
}
/* Caps preview content to fit inside the file-preview Modal.
300px reserves room for pathContent <pre>, Modal.Header, Modal.Actions row,
inner content (e.g. STL dimensions banner), and modal padding.
Use 100dvh so mobile browser chrome (URL bar) is accounted for. */
.preview-fit {
width: 100%;
height: calc(100dvh - 300px);
max-height: calc(100dvh - 300px);
min-height: 240px;
overflow: hidden;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
/* Fresnel (Media) wraps iframes in a div which would otherwise shrink to the
default iframe size; make it fill the preview so the iframe's 100% works. */
.preview-fit .fresnel-container {
width: 100%;
height: 100%;
}
td.file-path {
cursor: pointer;
}
/* Necessary until react-semantic-toasts is upgraded to Node 18 */
.ui-alerts {
position: fixed;
z-index: 2060;
padding: 24px;
}
.ui-alerts.top-right {
top: 20px;
right: 20px;
}
textarea.otp {
width: 100%;
color: #333;
}
.inline-header h1 {
display: inline-block;
}
.inline-header h2 {
display: inline-block;
}
.inline-header h3 {
display: inline-block;
}
.inline-header h4 {
display: inline-block;
}
.inline-header h5 {
display: inline-block;
}
.inline-header span {
margin-left: 1em;
}
.card-icon {
min-height: 163px;
text-align: center;
padding-top: 53px;
}
.card-icon.inverted {
background-color: #222222;
}
.modal .inverted {
border-color: #888888;
}
.modal .header.inverted {
color: #DDDDDD !important;
background-color: #171616 !important;
}
.modal .content.inverted {
color: #DDDDDD !important;
border-color: #888888 !important;
background-color: #171616 !important;
}
.modal .actions.inverted {
color: #DDDDDD !important;
border-color: #888888 !important;
background-color: #171616 !important;
}
.modal.inverted i.close {
color: #DDDDDD !important;
}
/* The accordion has no background of its own; it inherits whatever container it sits in (Modal
content #171616, Segment #1B1C1D, the page body, etc.). This matches how the light theme already
renders accordions (transparent), and avoids a darker band when the parent isn't #171616.
Direct children only, so nested components that use the `content`/`title` class names (e.g. a
Message's Message.Content) are not affected. */
.ui.inverted.accordion,
.ui.inverted.accordion > .title,
.ui.inverted.accordion > .content {
background-color: transparent !important;
}
/* Semantic UI paints a definition table's empty corner cell white (background on the inverted
variant, white box-shadows on the celled/plain variants) to fake a "cut-out" corner on a white
page. Our dark theme has a dark page, so the corner must be transparent with no shadow. */
.ui.inverted.definition.table thead:not(.full-width) th:first-child,
.ui.inverted.definition.table tfoot:not(.full-width) th:first-child,
.ui.inverted.celled.definition.table thead:not(.full-width) th:first-child,
.ui.inverted.celled.definition.table tfoot:not(.full-width) th:first-child {
background: transparent !important;
box-shadow: none !important;
}
/* Mobile-responsive Confirm modal */
.ui.modal.themed-confirm {
max-width: 95vw;
}
.clickable {
cursor: pointer;
}
.segment.inverted {
border: 1px solid #ffffff22 !important;
}
.inverted label {
color: #DDDDDD !important;
}
.table-ellipsis td.column-ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 0; /* Ensures the content doesn't exceed the cell's width */
min-width: 25em; /* About iPhone SE width */
}
.card-title-ellipsis {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
.search-container {
display: flex;
justify-content: flex-start;
}
.search-input {
flex-grow: 1;
}
.search-clear {
margin: 10px;
}
.icon.divider {
color: rgb(0, 0, 0, 0.4) !important;
}
.divider.inverted {
color: rgb(255, 255, 255, 0.6) !important;
}
.video-player {
display: block;
margin: 0 auto; /* Center the video horizontally */
}
.audio-poster-container {
position: relative;
display: block;
text-align: center;
}
.audio-poster-overlay {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: rgba(255, 255, 255, 0.85);
text-shadow: 0 0 20px rgba(0, 0, 0, 0.6);
pointer-events: none;
}
table.ratio-table td.equal-width {
width: 48%;
}
table.ratio-table td.min-width {
width: auto;
}
/* CollectionEditForm styles */
.required-indicator {
color: red;
}
.action-button-spacing {
margin-top: 1em;
}
/* Form loading skeleton */
.form-skeleton-field {
margin-bottom: 1.5em;
}
.form-skeleton-label {
height: 14px;
width: 80px;
margin-bottom: 8px;
background: linear-gradient(90deg, #e0e0e0 25%, #f0f0f0 50%, #e0e0e0 75%);
background-size: 200% 100%;
animation: skeleton-shimmer 1.5s infinite;
border-radius: 3px;
}
.form-skeleton-input {
height: 38px;
width: 100%;
background: linear-gradient(90deg, #e0e0e0 25%, #f0f0f0 50%, #e0e0e0 75%);
background-size: 200% 100%;
animation: skeleton-shimmer 1.5s infinite;
border-radius: 4px;
}
.form-skeleton-textarea {
height: 80px;
width: 100%;
background: linear-gradient(90deg, #e0e0e0 25%, #f0f0f0 50%, #e0e0e0 75%);
background-size: 200% 100%;
animation: skeleton-shimmer 1.5s infinite;
border-radius: 4px;
}
.form-skeleton-button {
height: 42px;
width: 100px;
background: linear-gradient(90deg, #e0e0e0 25%, #f0f0f0 50%, #e0e0e0 75%);
background-size: 200% 100%;
animation: skeleton-shimmer 1.5s infinite;
border-radius: 4px;
}
@keyframes skeleton-shimmer {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}
/* Dark mode skeleton */
.inverted .form-skeleton-label,
.inverted .form-skeleton-input,
.inverted .form-skeleton-textarea,
.inverted .form-skeleton-button {
background: linear-gradient(90deg, #333 25%, #444 50%, #333 75%);
background-size: 200% 100%;
animation: skeleton-shimmer 1.5s infinite;
}
/* Sticky footer for file browser */
.sticky-footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 0.5em 1em;
background-color: #f9fafb;
border-top: 1px solid rgba(34, 36, 38, 0.15);
z-index: 100;
}
.sticky-footer.inverted {
background-color: #1b1c1d;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
/* Drag selection visual feedback for FileBrowser */
tr.drag-selecting td {
background-color: rgba(33, 133, 208, 0.15) !important;
}
.inverted tr.drag-selecting td {
background-color: rgba(33, 133, 208, 0.25) !important;
}
/* Drag deselection visual feedback (red tint) */
tr.drag-deselecting td {
background-color: rgba(219, 40, 40, 0.15) !important;
}
.inverted tr.drag-deselecting td {
background-color: rgba(219, 40, 40, 0.25) !important;
}
/* Prevent text selection during drag */
.file-browser-dragging {
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
/* Filter input and collapse-all button: right-aligned on desktop, full width on mobile (below). */
.file-browser-filter-container {
display: flex;
justify-content: flex-end;
margin-bottom: 0.5em;
}
/* Double the default input width on desktop. */
.ui.input.file-browser-filter {
width: 34em;
max-width: 100%;
}
@media only screen and (max-width: 700px) {
.hide-on-mobile {
display: none !important;
}
.file-browser-filter-container {
justify-content: flex-start;
}
/* Fill the row, but stay on one line with the collapse-all button. */
.ui.input.file-browser-filter {
flex: 1 1 auto;
width: auto;
}
}
/* Ensure step icons are always visible, even when disabled */
.ui.steps .step.disabled > .icon,
.ui.steps .step.disabled > i.icon,
.ui.steps .disabled.step > .icon,
.ui.steps .disabled.step > i.icon {
opacity: 0.45 !important;
display: inline-block !important;
visibility: visible !important;
width: auto !important;
height: auto !important;
color: rgba(0, 0, 0, 0.87) !important;
}
/* Ensure the icon glyph (::before) is visible for disabled steps */
.ui.steps .step.disabled > .icon:before,
.ui.steps .step.disabled > i.icon:before,
.ui.steps .disabled.step > .icon:before,
.ui.steps .disabled.step > i.icon:before {
opacity: 0.45 !important;
visibility: visible !important;
color: rgba(0, 0, 0, 0.87) !important;
}
/* Inventory "PDF" export: the printable table is hidden on screen and becomes the only
visible content when printing, so a user can use the browser dialog to Save as PDF. */
.inventory-print {
display: none;
}
@media print {
body * {
visibility: hidden;
}
.inventory-print,
.inventory-print * {
visibility: visible;
}
.inventory-print {
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
color: #000;
}
.inventory-print h1 {
font-size: 18pt;
margin: 0 0 0.25em;
}
.inventory-print h2 {
font-size: 13pt;
margin: 1.25em 0 0.5em;
}
.inventory-print-meta {
font-size: 9pt;
color: #444;
margin: 0 0 0.75em;
}
.inventory-print table {
width: 100%;
border-collapse: collapse;
font-size: 10pt;
}
.inventory-print th,
.inventory-print td {
border: 1px solid #999;
padding: 4px 6px;
text-align: left;
vertical-align: top;
}
/* Repeat the header row at the top of each printed page. */
.inventory-print thead {
display: table-header-group;
}
.inventory-print tr {
page-break-inside: avoid;
}
/* The supply-plan shopping list reuses the .inventory-print element styling (h1/table/etc.) but is a separate
printable block. By default (e.g. the Export tab's whole-inventory PDF) it is hidden; it becomes the ONLY
printed block when the supply plan toggles `body.printing-shopping` just before window.print(). */
.shopping-print,
.shopping-print * {
visibility: hidden;
}
.shopping-print {
display: none;
}
body.printing-shopping .inventory-print:not(.shopping-print),
body.printing-shopping .inventory-print:not(.shopping-print) * {
visibility: hidden;
}
body.printing-shopping .inventory-print:not(.shopping-print) {
display: none;
}
body.printing-shopping .shopping-print,
body.printing-shopping .shopping-print * {
visibility: visible;
}
body.printing-shopping .shopping-print {
display: block;
}
}