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;
+ }
+ }
+ }
+ }
+ }
+ }
+}