From cb1df6f29eab1a059c05ca7cf1ecf67894083fc5 Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sun, 10 May 2026 15:16:19 +0100 Subject: [PATCH] Update SCSS --- index.html | 10 + src/index.scss | 280 +-------------- src/style/_app-shell.scss | 70 ++++ src/style/_control-dock.scss | 35 ++ src/style/_garden-prompt.scss | 137 +++++++ src/style/_motion.scss | 34 ++ src/style/_panels.scss | 142 ++++++++ src/style/_range-input.scss | 49 +++ src/style/_toolbar.scss | 653 ++++++++++++++++++++++++++++++++++ 9 files changed, 1136 insertions(+), 274 deletions(-) create mode 100644 src/style/_app-shell.scss create mode 100644 src/style/_control-dock.scss create mode 100644 src/style/_garden-prompt.scss create mode 100644 src/style/_motion.scss create mode 100644 src/style/_panels.scss create mode 100644 src/style/_range-input.scss create mode 100644 src/style/_toolbar.scss diff --git a/index.html b/index.html index 948774e..5bcb619 100644 --- a/index.html +++ b/index.html @@ -123,6 +123,16 @@ aria-label="Eraser size" /> + diff --git a/src/index.scss b/src/index.scss index 8c4500a..e4d6608 100644 --- a/src/index.scss +++ b/src/index.scss @@ -1,275 +1,7 @@ -@use 'style/mixins' as *; @use 'style/common'; - -html > body { - width: 100%; - height: 100%; - display: flex; - position: relative; - - > .canvas-container { - height: 100%; - width: 100%; - display: flex; - - > canvas { - height: 100%; - width: 100%; - touch-action: none; - cursor: - url('../assets/icons/brush.svg') 0 24, - auto; - } - - > .errors-container { - position: absolute; - top: 0; - left: 0; - margin: var(--normal-margin); - - pre { - font-size: 20px; - color: red; - } - } - - .counters { - @include blurred-background(white); - position: absolute; - border-radius: var(--border-radius); - padding: var(--small-margin); - - @include on-large-screen { - top: var(--normal-margin); - right: var(--normal-margin); - } - - @include on-small-screen { - bottom: var(--normal-margin); - right: var(--normal-margin); - } - } - } - - > aside { - @include blurred-background(#fff); - box-shadow: var(--shadow); - display: flex; - position: absolute; - overflow: hidden; - - @include on-large-screen { - top: 50%; - left: 0; - transform: translateY(-50%); - max-height: 350px; - } - - @include on-small-screen { - top: 0; - left: 50%; - transform: translateX(-50%); - flex-direction: column; - } - - transition: opacity var(--transition-time-long); - border-radius: var(--border-radius); - margin: var(--small-margin); - - > nav.buttons { - @include center-children; - justify-content: space-evenly; - - @include on-large-screen { - flex-direction: column; - } - - > button { - position: relative; - border: none; - background-color: transparent; - cursor: pointer; - - @include square(var(--icon-size)); - margin: var(--small-margin); - - &::before, - &::after { - content: ''; - position: absolute; - top: 0; - left: 0; - height: 100%; - width: 100%; - } - - &::before { - background-color: var(--accent-color); - - @include on-large-screen { - width: 0; - border-radius: 0 var(--border-radius) var(--border-radius) 0; - transition: - background-color var(--transition-time), - width var(--transition-time); - left: calc(-1 * var(--small-margin)); - height: 140%; - top: 50%; - transform: translateY(-50%); - } - - @include on-small-screen { - height: 0; - border-radius: 0 0 var(--border-radius) var(--border-radius); - transition: - background-color var(--transition-time), - height var(--transition-time); - top: calc(-1 * var(--small-margin)); - width: 140%; - left: 50%; - transform: translateX(-50%); - } - } - - &::after { - background-color: var(--accent-color); - - transition: - transform var(--transition-time), - background-color var(--transition-time); - - mask-repeat: no-repeat; - - @include square(var(--icon-size)); - } - - &.active { - &::before { - @include on-large-screen { - width: calc(100% + 2 * var(--small-margin)); - } - - @include on-small-screen { - height: calc(100% + 2 * var(--small-margin)); - } - } - - &::after { - background-color: white; - } - } - - &:hover::after { - transform: scale(1.15); - } - - &.info::after { - mask-image: url('../assets/icons/info.svg'); - } - &.maximize-full-screen::after { - mask-image: url('../assets/icons/maximize.svg'); - } - &.minimize-full-screen::after { - mask-image: url('../assets/icons/minimize.svg'); - } - &.settings::after { - mask-image: url('../assets/icons/settings.svg'); - } - &.restart::after { - mask-image: url('../assets/icons/restart.svg'); - } - } - } - - > main.pages { - overflow-x: hidden; - overflow-y: auto; - scrollbar-width: thin; - scrollbar-color: var(--main-color) transparent; - &::-webkit-scrollbar-track, - &::-webkit-scrollbar { - background-color: transparent; - width: 6px; - } - &::-webkit-scrollbar-thumb { - background-color: var(--main-color); - border-radius: var(--border-radius); - } - - &, - > * { - transition: - width var(--transition-time-long), - height var(--transition-time-long); - - @include on-large-screen { - width: max(500px, 10vw); - } - - @include on-small-screen { - height: max(500px, 70vh); - } - } - - &.hidden { - @include on-large-screen { - width: 0; - } - - @include on-small-screen { - height: 0; - } - } - - > section { - padding: var(--normal-margin); - display: flex; - flex-direction: column; - - .slider { - $track-height: 12px; - margin-bottom: var(--small-margin); - user-select: none; - - p { - display: flex; - justify-content: space-between; - } - - input[type='range'] { - width: 100%; - height: $track-height; - appearance: none; - background: transparent; - outline: none; - border-radius: 1000px; - - &::-webkit-slider-runnable-track { - appearance: none; - cursor: pointer; - border-radius: 1000px; - @include square(15px); - background: var(--accent-color); - } - - &::-webkit-slider-thumb { - appearance: none; - cursor: pointer; - border-radius: 1000px; - $size: 24px; - @include square($size); - background: white; - box-shadow: 0 0 5px 1px var(--accent-color); - - transform: translateY(-5px); - transition: transform var(--transition-time); - &:hover { - transform: translateY(-5px) scale(1.1); - } - } - } - } - } - } - } -} +@use 'style/app-shell'; +@use 'style/garden-prompt'; +@use 'style/control-dock'; +@use 'style/toolbar'; +@use 'style/panels'; +@use 'style/motion'; diff --git a/src/style/_app-shell.scss b/src/style/_app-shell.scss new file mode 100644 index 0000000..5a942c7 --- /dev/null +++ b/src/style/_app-shell.scss @@ -0,0 +1,70 @@ +html > body { + width: 100%; + min-height: 100vh; + min-height: 100dvh; + height: 100vh; + height: 100dvh; + overflow: hidden; + display: flex; + position: relative; + background: var(--garden-background, #10151f); + + > .canvas-container { + min-height: 100vh; + min-height: 100dvh; + height: 100%; + width: 100%; + display: flex; + position: relative; + overflow: hidden; + + > canvas { + height: 100%; + width: 100%; + touch-action: none; + cursor: + url('../../assets/icons/brush.svg') 0 24, + auto; + } + + > .eraser-preview { + position: absolute; + top: 0; + left: 0; + z-index: 1; + width: var(--eraser-preview-size, 96px); + height: var(--eraser-preview-size, 96px); + border: 2px solid rgb(255 234 228 / 88%); + border-radius: 50%; + background: rgb(255 140 117 / 13%); + box-shadow: + 0 0 0 1px rgb(255 88 70 / 34%), + 0 0 26px rgb(255 118 92 / 24%); + opacity: 0; + pointer-events: none; + transform: translate(-50%, -50%); + transition: + opacity var(--transition-time), + width var(--transition-time), + height var(--transition-time); + mix-blend-mode: screen; + + &.visible { + opacity: 1; + } + } + + > .errors-container { + position: absolute; + top: 0; + left: 0; + margin: var(--normal-margin); + z-index: 5; + + pre { + font-size: 20px; + color: red; + } + } + } +} diff --git a/src/style/_control-dock.scss b/src/style/_control-dock.scss new file mode 100644 index 0000000..6267c25 --- /dev/null +++ b/src/style/_control-dock.scss @@ -0,0 +1,35 @@ +html > body > aside.control-dock { + position: absolute; + left: 50%; + bottom: calc(0.75rem + env(safe-area-inset-bottom)); + z-index: 4; + width: min(calc(100vw - 1rem), 980px); + transform: translateX(-50%); + visibility: visible; + pointer-events: none; + transition: + opacity var(--transition-time-long), + transform var(--transition-time-long), + visibility 0s; + + > .toolbar-row, + > .pages { + pointer-events: auto; + } + + &.menu-hidden { + opacity: 0; + visibility: hidden; + transform: translate(-50%, 10px); + pointer-events: none; + transition: + opacity var(--transition-time-long), + transform var(--transition-time-long), + visibility 0s var(--transition-time-long); + + > .toolbar-row, + > .pages { + pointer-events: none; + } + } +} diff --git a/src/style/_garden-prompt.scss b/src/style/_garden-prompt.scss new file mode 100644 index 0000000..ed56320 --- /dev/null +++ b/src/style/_garden-prompt.scss @@ -0,0 +1,137 @@ +@use 'mixins' as *; + +html > body > .canvas-container > .garden-prompt { + position: absolute; + left: 50%; + bottom: calc(7.25rem + env(safe-area-inset-bottom)); + transform: translateX(-50%); + max-width: min(92vw, 780px); + color: white; + text-align: center; + font-size: 46px; + line-height: 1.15; + text-shadow: 0 2px 18px rgb(0 0 0 / 60%); + pointer-events: none; + z-index: 2; + + &:empty { + display: none; + } + + &.draw-hint { + display: flex; + align-items: center; + top: calc(1.25rem + env(safe-area-inset-top)); + bottom: auto; + gap: 16px; + width: max-content; + min-height: 78px; + max-width: min(88vw, 460px); + padding: 12px 18px 12px 14px; + border: 1px solid rgb(255 255 255 / 16%); + border-radius: 8px; + background: rgb(10 12 16 / 50%); + box-shadow: + 0 14px 42px rgb(0 0 0 / 28%), + inset 0 0 0 1px rgb(255 255 255 / 5%); + backdrop-filter: blur(12px); + color: rgb(255 255 255 / 94%); + font: + 600 20px/1.2 'Open Sans', + sans-serif; + text-shadow: 0 1px 12px rgb(0 0 0 / 58%); + } + + .draw-hint-mark { + width: 128px; + height: 72px; + flex: 0 0 128px; + overflow: visible; + } + + .draw-hint-shadow, + .draw-hint-stroke { + fill: none; + stroke-linecap: round; + stroke-linejoin: round; + } + + .draw-hint-shadow { + stroke: rgb(0 0 0 / 42%); + stroke-width: 10px; + } + + .draw-hint-stroke { + stroke: color-mix(in srgb, var(--accent-color) 74%, white); + stroke-width: 5px; + stroke-dasharray: 154; + animation: draw-hint-stroke 2.4s ease-in-out infinite; + filter: drop-shadow( + 0 0 12px color-mix(in srgb, var(--accent-color) 60%, transparent) + ); + } + + .draw-hint-start { + fill: rgb(255 255 255 / 64%); + } + + .draw-hint-end { + fill: white; + stroke: color-mix(in srgb, var(--accent-color) 72%, transparent); + stroke-width: 5px; + transform-origin: 116px 42px; + animation: draw-hint-tap 2.4s ease-in-out infinite; + } + + @include on-small-screen { + bottom: calc(10rem + env(safe-area-inset-bottom)); + font-size: 24px; + + &.draw-hint { + top: calc(0.75rem + env(safe-area-inset-top)); + bottom: auto; + gap: 10px; + min-height: 58px; + max-width: min(92vw, 340px); + padding: 9px 12px 9px 10px; + font-size: 16px; + } + + .draw-hint-mark { + width: 96px; + height: 54px; + flex-basis: 96px; + } + } +} + +@keyframes draw-hint-stroke { + 0%, + 18% { + stroke-dashoffset: 154; + } + + 58%, + 100% { + stroke-dashoffset: 0; + } +} + +@keyframes draw-hint-tap { + 0%, + 16% { + opacity: 0; + transform: scale(0.72); + } + + 36%, + 74% { + opacity: 1; + transform: scale(1); + } + + 100% { + opacity: 0.76; + transform: scale(0.88); + } +} diff --git a/src/style/_motion.scss b/src/style/_motion.scss new file mode 100644 index 0000000..005a69f --- /dev/null +++ b/src/style/_motion.scss @@ -0,0 +1,34 @@ +@media (prefers-reduced-motion: reduce) { + html > body { + > .canvas-container > .garden-prompt { + .draw-hint-stroke { + stroke-dashoffset: 0; + } + + .draw-hint-end { + opacity: 1; + transform: none; + } + } + + > aside.control-dock { + &, + &.menu-hidden { + transform: translateX(-50%); + } + + > .toolbar-row { + button:hover, + button:active, + > .toolbar-shell > .garden-controls > .swatches > .eraser-size-control:hover, + > .toolbar-shell > .garden-controls > .swatches > .mirror-segment-control:hover { + transform: none; + } + + > .toolbar-shell > nav.buttons > button:hover::after { + transform: none; + } + } + } + } +} diff --git a/src/style/_panels.scss b/src/style/_panels.scss new file mode 100644 index 0000000..401dfe7 --- /dev/null +++ b/src/style/_panels.scss @@ -0,0 +1,142 @@ +@use 'mixins' as *; +@use 'range-input' as *; + +html > body > aside.control-dock > .pages { + @include blurred-background(#fff); + width: min(calc(100vw - 1rem), 560px); + max-height: min(58vh, 520px); + max-height: min(58dvh, 520px); + margin: 0 auto 10px; + overflow-x: hidden; + overflow-y: auto; + border: 1px solid rgb(255 255 255 / 54%); + border-radius: 8px; + box-shadow: + 0 18px 48px rgb(0 0 0 / 28%), + 0 2px 10px rgb(0 0 0 / 16%); + scrollbar-width: thin; + scrollbar-color: var(--main-color) transparent; + transition: + max-height var(--transition-time-long), + opacity var(--transition-time-long), + transform var(--transition-time-long), + margin-bottom var(--transition-time-long); + + &::-webkit-scrollbar-track, + &::-webkit-scrollbar { + background-color: transparent; + width: 6px; + } + + &::-webkit-scrollbar-thumb { + background-color: var(--main-color); + border-radius: 8px; + } + + &:focus-visible { + outline: 2px solid white; + outline-offset: 3px; + } + + &.hidden { + max-height: 0; + margin-bottom: 0; + border-color: transparent; + opacity: 0; + pointer-events: none; + box-shadow: none; + transform: translateY(8px); + visibility: hidden; + } + + > section { + display: flex; + flex-direction: column; + padding: var(--normal-margin); + + h1 { + font-size: 2rem; + line-height: 1.1; + } + + p { + @include main-font(); + margin-bottom: var(--small-margin); + line-height: 1.65; + } + + a { + color: var(--accent-color); + } + + .slider { + $track-height: 8px; + $thumb-size: 22px; + margin-bottom: var(--small-margin); + user-select: none; + + p { + display: flex; + justify-content: space-between; + gap: var(--small-margin); + margin-bottom: 0.35rem; + font-size: 0.95rem; + } + + input[type='range'] { + @include settings-range-input(); + + &::-webkit-slider-runnable-track { + @include range-track(rgb(49 52 63 / 14%), $track-height, 1000px, null); + } + + &::-webkit-slider-thumb { + @include range-thumb-base( + $thumb-size, + $thumb-size, + 2px solid var(--accent-color), + 1000px + ); + margin-top: -7px; + appearance: none; + background: white; + box-shadow: 0 3px 10px rgb(0 0 0 / 20%); + transition: transform var(--transition-time); + + &:hover { + transform: scale(1.08); + } + } + + &::-moz-range-track { + @include range-track(rgb(49 52 63 / 14%), $track-height, 1000px, null); + } + + &::-moz-range-thumb { + @include range-thumb-base( + $thumb-size, + $thumb-size, + 2px solid var(--accent-color), + 1000px + ); + background: white; + box-shadow: 0 3px 10px rgb(0 0 0 / 20%); + } + } + } + + .large-button { + margin: var(--small-margin) 0 0 auto; + border-radius: 8px; + } + } + + @include on-small-screen { + max-height: min(54vh, 500px); + max-height: min(54dvh, 500px); + + > section { + padding: var(--small-margin); + } + } +} diff --git a/src/style/_range-input.scss b/src/style/_range-input.scss new file mode 100644 index 0000000..a55899e --- /dev/null +++ b/src/style/_range-input.scss @@ -0,0 +1,49 @@ +@mixin toolbar-range-input() { + position: relative; + z-index: 1; + width: 100%; + height: 100%; + appearance: none; + background: transparent; + cursor: ew-resize; + outline: none; + touch-action: pan-y; + + &:focus-visible { + outline: 2px solid white; + outline-offset: 2px; + border-radius: 8px; + } +} + +@mixin settings-range-input() { + width: 100%; + height: 44px; + appearance: none; + background: transparent; + outline: none; +} + +@mixin range-track( + $background, + $height: 7px, + $border-radius: 999px, + $box-shadow: inset 0 1px 2px rgb(0 0 0 / 24%) +) { + height: $height; + cursor: pointer; + border-radius: $border-radius; + background: $background; + + @if $box-shadow != null { + box-shadow: $box-shadow; + } +} + +@mixin range-thumb-base($width, $height, $border, $border-radius) { + width: $width; + height: $height; + cursor: pointer; + border: $border; + border-radius: $border-radius; +} diff --git a/src/style/_toolbar.scss b/src/style/_toolbar.scss new file mode 100644 index 0000000..28ac9e2 --- /dev/null +++ b/src/style/_toolbar.scss @@ -0,0 +1,653 @@ +@use 'mixins' as *; +@use 'range-input' as *; + +html > body > aside.control-dock > .toolbar-row { + display: flex; + align-items: stretch; + justify-content: center; + width: fit-content; + max-width: 100%; + margin: 0 auto; + gap: clamp(6px, 1.8vw, 14px); + color: rgb(245 250 244 / 92%); + font: + 600 13px/1 'Open Sans', + sans-serif; + + button { + min-width: 44px; + min-height: 44px; + border: 0; + font: inherit; + cursor: pointer; + transition: + background-color var(--transition-time), + border-color var(--transition-time), + color var(--transition-time), + box-shadow var(--transition-time), + transform var(--transition-time); + + &:focus-visible { + outline: 2px solid white; + outline-offset: 2px; + } + } + + > .toolbar-shell { + display: grid; + grid-template-columns: minmax(0, 1fr); + grid-template-areas: + 'swatches' + 'nav'; + align-items: center; + justify-content: center; + gap: 8px; + min-width: 0; + min-height: 86px; + padding: 8px 9px; + border: 1px solid rgb(255 255 255 / 10%); + border-radius: 10px; + background: rgb(12 14 16 / 74%); + backdrop-filter: blur(16px); + box-shadow: + 0 10px 30px rgb(0 0 0 / 22%), + 0 1px 3px rgb(0 0 0 / 18%); + } + + > .vibe-button { + display: grid; + place-items: center; + position: relative; + width: 52px; + height: auto; + min-height: 66px; + flex: 0 0 auto; + padding: 0; + border: 0; + border-radius: 0; + background: transparent; + color: rgb(255 255 255 / 70%); + font-size: 0; + line-height: 1; + text-shadow: none; + box-shadow: none; + + &::before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 18px; + height: 18px; + border-color: currentColor; + border-style: solid; + border-width: 0 0 3px 3px; + transform: translate(-35%, -50%) rotate(45deg); + } + + &.next-vibe::before { + border-width: 3px 3px 0 0; + transform: translate(-65%, -50%) rotate(45deg); + } + + &:hover { + background: transparent; + color: color-mix(in srgb, var(--accent-color) 70%, white); + box-shadow: none; + transform: translateY(-2px); + } + + &:active { + transform: translateY(0); + } + } + + > .toolbar-shell > nav.buttons { + grid-area: nav; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + gap: 4px; + min-width: 0; + padding-top: 7px; + border-top: 1px solid rgb(255 255 255 / 12%); + + > button { + position: relative; + width: 44px; + height: 44px; + border: 1px solid transparent; + border-radius: 8px; + background: transparent; + + &::after { + content: ''; + position: absolute; + inset: 0; + z-index: 1; + width: 20px; + height: 20px; + margin: auto; + background-color: rgb(245 250 244 / 76%); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + transition: + background-color var(--transition-time), + transform var(--transition-time); + } + + &:hover, + &.active { + border-color: rgb(255 255 255 / 10%); + background: rgb(255 255 255 / 9%); + } + + &:hover::after { + transform: scale(1.08); + } + + &.active { + border-color: color-mix(in srgb, var(--accent-color) 55%, white 15%); + background: color-mix(in srgb, var(--accent-color) 30%, transparent); + box-shadow: none; + } + + &.active::after { + background-color: white; + } + + &.info::after { + mask-image: url('../../assets/icons/info.svg'); + } + + &.maximize-full-screen::after { + mask-image: url('../../assets/icons/maximize.svg'); + } + + &.minimize-full-screen::after { + mask-image: url('../../assets/icons/minimize.svg'); + } + + &.settings::after { + mask-image: url('../../assets/icons/settings.svg'); + } + + &.sound::after { + mask-image: url('../../assets/icons/sound.svg'); + } + + &.sound.muted::before { + content: ''; + position: absolute; + inset: 0; + z-index: 2; + width: 2px; + height: 28px; + margin: auto; + border-radius: 999px; + background: white; + transform: rotate(-45deg); + transform-origin: center; + } + + &.sound.muted::after { + background-color: rgb(255 255 255 / 46%); + } + + &.export-4k::after { + mask-image: url('../../assets/icons/download.svg'); + } + + &.restart::after { + mask-image: url('../../assets/icons/restart.svg'); + } + } + + > .export-status { + flex: 0 1 140px; + min-height: 20px; + max-width: 140px; + overflow: hidden; + color: rgb(255 255 255 / 82%); + font-size: 13px; + line-height: 1.2; + text-overflow: ellipsis; + white-space: nowrap; + + &:empty { + display: none; + } + } + } + + > .toolbar-shell > .garden-controls { + grid-area: swatches; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + gap: 12px; + min-width: 0; + padding: 0 4px; + + > .swatches { + display: flex; + align-items: center; + justify-content: center; + gap: 12px; + min-height: 58px; + padding: 6px 10px; + + > button { + position: relative; + width: 44px; + height: 44px; + border: 2px solid rgb(255 255 255 / 54%); + border-radius: 50%; + box-shadow: + inset 0 0 0 1px rgb(0 0 0 / 16%), + 0 3px 10px rgb(0 0 0 / 22%); + + &:hover { + transform: translateY(-2px); + } + + &.active { + outline: 2px solid rgb(255 255 255 / 96%); + outline-offset: 3px; + box-shadow: + inset 0 0 0 1px rgb(0 0 0 / 14%), + 0 0 0 7px color-mix(in srgb, var(--accent-color) 52%, transparent), + 0 7px 18px rgb(0 0 0 / 26%); + } + } + + > .eraser-size-control { + --eraser-control-scale: 1; + --eraser-progress: 33%; + + position: relative; + display: grid; + align-items: center; + width: 184px; + height: 46px; + flex: 0 0 184px; + padding: 0 12px; + overflow: hidden; + border: 1px solid rgb(255 255 255 / 14%); + border-radius: 8px; + background: + radial-gradient( + circle at 24% 78%, + rgb(255 226 215 / 42%) 0 1px, + transparent 1.5px + ), + radial-gradient( + circle at 47% 72%, + rgb(255 226 215 / 34%) 0 1px, + transparent 1.5px + ), + radial-gradient( + circle at 67% 81%, + rgb(255 226 215 / 38%) 0 1px, + transparent 1.5px + ), + linear-gradient(180deg, rgb(255 255 255 / 9%), rgb(255 255 255 / 4%)); + box-shadow: + inset 0 0 0 1px rgb(255 255 255 / 6%), + 0 3px 10px rgb(0 0 0 / 18%); + cursor: ew-resize; + transition: + border-color var(--transition-time), + background-color var(--transition-time), + box-shadow var(--transition-time), + transform var(--transition-time); + + &::before { + content: ''; + position: absolute; + right: 12px; + bottom: 8px; + left: 12px; + height: 2px; + border-radius: 999px; + background: linear-gradient( + 90deg, + rgb(255 140 117 / 56%) 0 var(--eraser-progress), + rgb(255 255 255 / 18%) var(--eraser-progress) 100% + ); + box-shadow: 0 1px 4px rgb(0 0 0 / 22%); + } + + &:hover { + transform: translateY(-2px); + border-color: rgb(255 255 255 / 24%); + } + + &.active { + border-color: rgb(255 212 202 / 72%); + background-color: rgb(255 140 117 / 11%); + box-shadow: + inset 0 0 0 1px rgb(255 255 255 / 10%), + 0 0 0 5px rgb(255 140 117 / 34%), + 0 6px 15px rgb(0 0 0 / 22%); + } + + input[type='range'] { + @include toolbar-range-input(); + + &::-webkit-slider-runnable-track { + @include range-track( + linear-gradient( + 90deg, + rgb(255 140 117 / 72%) 0 var(--eraser-progress), + rgb(255 255 255 / 24%) var(--eraser-progress) 100% + ) + ); + } + + &::-webkit-slider-thumb { + @include range-thumb-base( + calc(34px * var(--eraser-control-scale)), + calc(21px * var(--eraser-control-scale)), + 2px solid rgb(255 239 233 / 94%), + calc(6px * var(--eraser-control-scale)) + ); + margin-top: calc((7px - (21px * var(--eraser-control-scale))) / 2); + appearance: none; + background: + linear-gradient( + 110deg, + transparent 0 12%, + rgb(255 255 255 / 44%) 13% 20%, + transparent 21% 100% + ), + linear-gradient( + 90deg, + #ff8fa3 0 52%, + rgb(54 46 51 / 78%) 53% 56%, + #f5eee5 57% 100% + ); + box-shadow: + inset 0 -2px 3px rgb(117 46 58 / 22%), + inset 0 2px 3px rgb(255 255 255 / 28%), + 0 4px 10px rgb(0 0 0 / 28%); + transform: rotate(-10deg); + transition: + height var(--transition-time), + margin-top var(--transition-time), + width var(--transition-time); + } + + &::-moz-range-track { + @include range-track( + linear-gradient( + 90deg, + rgb(255 140 117 / 72%) 0 var(--eraser-progress), + rgb(255 255 255 / 24%) var(--eraser-progress) 100% + ) + ); + } + + &::-moz-range-thumb { + @include range-thumb-base( + calc(34px * var(--eraser-control-scale)), + calc(21px * var(--eraser-control-scale)), + 2px solid rgb(255 239 233 / 94%), + calc(6px * var(--eraser-control-scale)) + ); + background: + linear-gradient( + 110deg, + transparent 0 12%, + rgb(255 255 255 / 44%) 13% 20%, + transparent 21% 100% + ), + linear-gradient( + 90deg, + #ff8fa3 0 52%, + rgb(54 46 51 / 78%) 53% 56%, + #f5eee5 57% 100% + ); + box-shadow: + inset 0 -2px 3px rgb(117 46 58 / 22%), + inset 0 2px 3px rgb(255 255 255 / 28%), + 0 4px 10px rgb(0 0 0 / 28%); + transform: rotate(-10deg); + transition: + height var(--transition-time), + width var(--transition-time); + } + } + } + + > .mirror-segment-control { + --mirror-progress: 0%; + --mirror-angle: 360deg; + + position: relative; + display: grid; + align-items: center; + width: 184px; + height: 46px; + flex: 0 0 184px; + padding: 0 12px; + overflow: hidden; + border: 1px solid rgb(255 255 255 / 14%); + border-radius: 8px; + background: + radial-gradient( + circle at 24% 78%, + rgb(197 255 234 / 38%) 0 1px, + transparent 1.5px + ), + radial-gradient( + circle at 47% 72%, + rgb(197 255 234 / 30%) 0 1px, + transparent 1.5px + ), + radial-gradient( + circle at 67% 81%, + rgb(197 255 234 / 34%) 0 1px, + transparent 1.5px + ), + linear-gradient(180deg, rgb(255 255 255 / 9%), rgb(255 255 255 / 4%)); + box-shadow: + inset 0 0 0 1px rgb(255 255 255 / 6%), + 0 3px 10px rgb(0 0 0 / 18%); + cursor: ew-resize; + transition: + border-color var(--transition-time), + background-color var(--transition-time), + box-shadow var(--transition-time), + transform var(--transition-time); + + &::before { + content: ''; + position: absolute; + right: 12px; + bottom: 8px; + left: 12px; + height: 2px; + border-radius: 999px; + background: linear-gradient( + 90deg, + rgb(148 233 203 / 56%) 0 var(--mirror-progress), + rgb(255 255 255 / 18%) var(--mirror-progress) 100% + ); + box-shadow: 0 1px 4px rgb(0 0 0 / 22%); + } + + &:hover { + transform: translateY(-2px); + border-color: rgb(255 255 255 / 24%); + } + + &.active { + border-color: rgb(167 245 219 / 74%); + background-color: rgb(92 206 177 / 12%); + box-shadow: + inset 0 0 0 1px rgb(255 255 255 / 10%), + 0 0 0 5px rgb(92 206 177 / 28%), + 0 6px 15px rgb(0 0 0 / 22%); + } + + input[type='range'] { + @include toolbar-range-input(); + + &::-webkit-slider-runnable-track { + @include range-track( + linear-gradient( + 90deg, + rgb(148 233 203 / 78%) 0 var(--mirror-progress), + rgb(255 255 255 / 24%) var(--mirror-progress) 100% + ) + ); + } + + &::-webkit-slider-thumb { + @include range-thumb-base(44px, 44px, 2px solid rgb(240 255 251 / 94%), 50%); + margin-top: -18.5px; + appearance: none; + background: + radial-gradient(circle, white 0 3px, rgb(9 20 18 / 78%) 3.5px 8px), + repeating-conic-gradient( + from -90deg, + rgb(218 255 241) 0 8deg, + rgb(8 22 19 / 94%) 8deg var(--mirror-angle) + ); + box-shadow: + inset 0 0 0 7px rgb(0 0 0 / 18%), + 0 0 0 5px rgb(92 206 177 / 16%), + 0 5px 14px rgb(0 0 0 / 30%); + transition: + box-shadow var(--transition-time), + transform var(--transition-time); + } + + &::-webkit-slider-thumb:hover { + box-shadow: + inset 0 0 0 7px rgb(0 0 0 / 18%), + 0 0 0 7px rgb(92 206 177 / 24%), + 0 6px 16px rgb(0 0 0 / 34%); + transform: scale(1.04); + } + + &::-moz-range-track { + @include range-track( + linear-gradient( + 90deg, + rgb(148 233 203 / 78%) 0 var(--mirror-progress), + rgb(255 255 255 / 24%) var(--mirror-progress) 100% + ) + ); + } + + &::-moz-range-thumb { + @include range-thumb-base(44px, 44px, 2px solid rgb(240 255 251 / 94%), 50%); + background: + radial-gradient(circle, white 0 3px, rgb(9 20 18 / 78%) 3.5px 8px), + repeating-conic-gradient( + from -90deg, + rgb(218 255 241) 0 8deg, + rgb(8 22 19 / 94%) 8deg var(--mirror-angle) + ); + box-shadow: + inset 0 0 0 7px rgb(0 0 0 / 18%), + 0 0 0 5px rgb(92 206 177 / 16%), + 0 5px 14px rgb(0 0 0 / 30%); + } + } + } + } + } + + @include on-small-screen { + width: 100%; + gap: 6px; + + > .vibe-button { + width: 44px; + min-height: 44px; + + &::before { + width: 14px; + height: 14px; + } + } + + > .toolbar-shell { + flex: 1 1 auto; + min-width: 0; + gap: 8px; + padding: 8px; + + > nav.buttons { + grid-area: nav; + justify-content: center; + gap: 2px; + padding-top: 7px; + border-top: 1px solid rgb(255 255 255 / 12%); + + > button { + width: 44px; + height: 44px; + + &::after { + width: 17px; + height: 17px; + } + } + + > .export-status { + flex-basis: 100%; + max-width: 100%; + text-align: center; + } + } + + > .garden-controls { + grid-area: swatches; + display: flex; + justify-content: center; + gap: 8px; + padding: 2px 4px; + + > .swatches { + flex-wrap: wrap; + justify-content: center; + gap: 9px; + row-gap: 8px; + min-height: 54px; + padding: 7px 8px; + + > .color-swatch { + width: 44px; + height: 44px; + } + + > .eraser-size-control { + width: clamp(104px, 31vw, 138px); + height: 44px; + flex-basis: clamp(104px, 31vw, 138px); + padding: 0 9px; + } + + > .mirror-segment-control { + width: clamp(104px, 31vw, 138px); + height: 44px; + flex-basis: clamp(104px, 31vw, 138px); + padding: 0 9px; + + &::before { + right: 9px; + left: 9px; + } + } + } + } + } + } +}