Files
yawn/server/web/assets/sculpt/styles.css
T
Ampandheaust 347b676cf1 Add core-powered web sculpting studio with tablet controls
Add pressure-aware worker sculpting, bounded shared input, project files and history, and compact icon navigation with an XYZ orbit gizmo.

Amp-Thread-ID: https://ampcode.com/threads/T-01a0b4b4-202c-73f1-984d-9a55c88f9c83
Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
2026-09-28 08:53:50 +00:00

524 lines
9.2 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Basecoat owns controls; these rules own the sculpt workspace and density. */
:root {
color-scheme: dark;
font-family:
ui-sans-serif,
system-ui,
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
sans-serif;
font-size: 14px;
}
body {
margin: 0;
height: 100dvh;
overflow: hidden;
overscroll-behavior: none;
}
[hidden] {
display: none !important;
}
#viewport {
position: fixed;
inset: 0;
overflow: hidden;
touch-action: none;
outline: none;
background: #20242b;
}
canvas {
display: block;
width: 100%;
height: 100%;
touch-action: none;
}
button,
input,
select,
summary {
-webkit-tap-highlight-color: transparent;
}
.tool-rail {
position: fixed;
z-index: 4;
top: max(12px, env(safe-area-inset-top));
left: max(8px, env(safe-area-inset-left));
max-height: calc(100dvh - 24px - env(safe-area-inset-bottom));
overflow-y: auto;
scrollbar-width: none;
display: grid;
gap: 6px;
}
.tool-rail .brushes,
.rail-group {
display: grid;
gap: 1px;
padding: 3px;
border-radius: 5px;
background: #22252bd9;
}
.icon-button.btn {
width: 38px;
height: 38px;
padding: 8px;
border: 0;
border-radius: 4px;
color: #d4d7db;
background: #22252bd9;
touch-action: none;
}
.tool-rail .icon-button.btn {
touch-action: pan-y;
}
.icon-button svg {
width: 22px;
height: 22px;
fill: none;
stroke: currentColor;
stroke-width: 1.6;
stroke-linecap: round;
stroke-linejoin: round;
pointer-events: none;
}
.icon-button.btn:hover {
background: #43484f;
}
.tool-rail .btn[aria-pressed="true"] {
color: #fff;
background: #386fa9;
}
.tool-rail > .btn {
margin-left: 3px;
}
#view-navigation {
position: fixed;
z-index: 4;
right: max(12px, env(safe-area-inset-right));
top: max(12px, env(safe-area-inset-top));
touch-action: none;
user-select: none;
}
#orbit-gizmo {
position: relative;
width: 104px;
height: 104px;
border-radius: 50%;
cursor: grab;
touch-action: none;
}
#orbit-gizmo:active {
cursor: grabbing;
}
#orbit-gizmo > svg {
position: absolute;
inset: 0;
width: 104px;
height: 104px;
pointer-events: none;
}
.axis-line {
stroke-width: 2;
}
.axis {
position: absolute;
width: 25px;
height: 25px;
padding: 0;
border: 1px solid var(--axis-color);
border-radius: 50%;
transform: translate(-50%, -50%);
background: var(--axis-color);
color: #15202c;
font-size: 12px;
font-weight: 600;
cursor: grab;
touch-action: none;
}
.axis.rear {
background: #30343bec;
}
.axis:hover {
filter: brightness(1.3);
}
.axis:focus-visible,
#orbit-gizmo:focus-visible {
outline: 2px solid white;
outline-offset: 3px;
}
.view-buttons {
display: flex;
justify-content: flex-end;
gap: 2px;
}
.view-buttons .btn {
width: 32px;
height: 32px;
padding: 7px;
border-radius: 50%;
}
.modified-label {
position: fixed;
z-index: 3;
top: max(8px, env(safe-area-inset-top));
font-size: 10px;
letter-spacing: 0.02em;
color: #b7bac1;
pointer-events: none;
}
.modified-label {
left: 62px;
}
.panel {
position: fixed;
z-index: 5;
top: max(12px, env(safe-area-inset-top));
padding: 10px;
background: var(--popover);
color: var(--popover-foreground);
border: 1px solid var(--border);
box-shadow: 0 8px 24px #0003;
max-height: calc(
100dvh - max(24px, env(safe-area-inset-top)) -
max(12px, env(safe-area-inset-bottom))
);
overflow: auto;
overscroll-behavior: contain;
scrollbar-width: thin;
touch-action: pan-y;
}
.tools-panel {
left: max(58px, calc(env(safe-area-inset-left) + 50px));
width: min(216px, calc(100vw - 74px));
border-radius: 6px;
}
.settings-panel {
left: max(58px, calc(env(safe-area-inset-left) + 50px));
width: min(264px, calc(100vw - 74px));
border-radius: 6px;
}
.panel-heading {
display: flex;
align-items: center;
justify-content: space-between;
height: 28px;
margin-bottom: 6px;
}
.panel-heading h2 {
font-size: 12px;
font-weight: 600;
}
.panel .btn {
height: 30px;
font-size: 12px;
padding-inline: 8px;
border-radius: 5px;
}
.panel-heading .btn {
width: 28px;
height: 28px;
font-size: 18px;
color: var(--muted-foreground);
}
.brushes {
display: grid;
gap: 2px;
}
.brushes .btn {
justify-content: space-between;
font-weight: 400;
}
.brushes .btn span {
color: var(--muted-foreground);
font-size: 10px;
}
.panel [aria-pressed="true"] {
background: var(--accent);
color: var(--accent-foreground);
box-shadow: inset 2px 0 0 #dedee4;
}
.control-section {
border-top: 1px solid var(--border);
margin-top: 8px;
padding-top: 8px;
}
label {
display: block;
font-size: 11px;
line-height: 18px;
}
output {
float: right;
color: var(--muted-foreground);
font-size: 10px;
font-variant-numeric: tabular-nums;
}
.panel input[type="range"] {
display: block;
width: 100%;
height: 24px;
margin: 0 0 4px;
touch-action: none;
}
.toggle-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
min-height: 32px;
cursor: pointer;
}
.toggle-row small {
display: block;
color: var(--muted-foreground);
font-size: 10px;
line-height: 16px;
}
.toggle-row input {
flex-shrink: 0;
}
.history,
.navigation,
.project-actions,
.settings-footer {
display: grid;
gap: 4px;
}
.history,
.settings-footer {
grid-template-columns: 1fr 1fr;
}
.navigation {
grid-template-columns: repeat(3, 1fr);
}
.wide {
width: 100%;
margin-top: 4px;
}
.project-name {
color: var(--muted-foreground);
font-size: 11px;
margin: 4px 0 10px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.project-actions {
grid-template-columns: repeat(3, 1fr);
}
#save {
grid-column: 1/-1;
}
.palm-row {
margin-top: 12px;
padding-bottom: 10px;
}
details {
border-top: 1px solid var(--border);
}
/* Avoid transient overlapping controls during the library's height animation. */
details::details-content {
transition: none;
}
summary {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 36px;
font-size: 12px;
cursor: pointer;
list-style: none;
}
summary::-webkit-details-marker {
display: none;
}
summary::after {
content: "+";
color: var(--muted-foreground);
}
details[open] > summary::after {
content: "−";
}
summary:focus-visible {
outline: 2px solid var(--ring);
outline-offset: 2px;
border-radius: 3px;
}
.disclosure-content {
padding: 4px 0 12px;
}
.settings-footer {
border-top: 1px solid var(--border);
padding-top: 8px;
}
.select {
width: 100%;
}
.panel .select {
height: 32px;
font-size: 12px;
}
.hint {
font-size: 11px;
line-height: 1.6;
color: var(--muted-foreground);
}
.pressure-meter {
height: 3px;
background: var(--muted);
margin: 8px 0;
border-radius: 2px;
overflow: hidden;
}
#pressure-fill {
width: 0;
height: 100%;
background: var(--foreground);
}
#curve {
display: block;
width: 100%;
height: 40px;
margin: 8px 0;
}
.curve-grid {
fill: none;
stroke: var(--border);
}
.curve-grid,
#curve-line {
stroke-width: 1;
}
#curve-line {
fill: none;
stroke: var(--foreground);
}
.swatches {
display: flex;
gap: 8px;
margin-top: 10px;
}
.swatches .btn {
width: 32px;
height: 32px;
padding: 6px;
border: 1px solid transparent;
}
.swatches .btn::before {
content: "";
width: 18px;
height: 18px;
background: var(--swatch);
border-radius: 50%;
}
.swatches .btn[aria-pressed="true"] {
border-color: var(--muted-foreground);
box-shadow: none;
}
#cursor {
position: absolute;
border: 1px solid #d0efdc;
border-radius: 50%;
pointer-events: none;
transform: translate(-50%, -50%);
}
#cursor i {
position: absolute;
width: 3px;
height: 3px;
top: 50%;
left: 50%;
border-radius: 50%;
background: #d0efdc;
transform: translate(-50%, -50%);
}
.status-toast {
position: fixed;
z-index: 8;
bottom: max(12px, env(safe-area-inset-bottom));
left: 50%;
transform: translateX(-50%);
max-width: min(400px, calc(100vw - 32px));
padding: 6px 10px;
border-radius: 5px;
background: var(--popover);
border: 1px solid var(--border);
color: var(--popover-foreground);
font-size: 11px;
text-align: center;
pointer-events: none;
opacity: 0;
}
.status-toast.visible {
opacity: 1;
}
.canvas-message {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: min(340px, calc(100% - 48px));
padding: 20px;
color: var(--popover-foreground);
background: var(--popover);
border: 1px solid var(--border);
border-radius: 8px;
}
.canvas-message h1 {
font-size: 16px;
font-weight: 600;
}
.canvas-message p {
margin: 10px 0 16px;
font-size: 12px;
color: var(--muted-foreground);
}
.dialog > form {
width: min(380px, calc(100vw - 32px));
overflow: auto;
}
.dialog label {
margin-bottom: 6px;
}
.dialog .hint {
margin-top: 8px;
}
.dialog dl {
font-size: 12px;
line-height: 1.6;
}
.dialog dt {
margin-top: 12px;
font-weight: 500;
}
.dialog dd {
color: var(--muted-foreground);
}
@media (any-pointer: coarse) {
.icon-button.btn {
width: 40px;
height: 40px;
}
.view-buttons .btn {
width: 34px;
height: 34px;
}
.panel .btn {
min-height: 36px;
}
.toggle-row,
summary {
min-height: 40px;
}
.panel input[type="range"] {
height: 32px;
}
}
@media (prefers-reduced-motion: reduce) {
.btn,
.dialog,
.dialog > * {
transition: none;
}
}