/* Dark is the default regardless of the system's own light/dark
   setting (a deliberate choice, not an oversight); light only applies
   when the theme toggle has set data-theme="light" on the root, read
   back from localStorage on load (see the blocking script in <head>,
   which sets that attribute before first paint to avoid a flash of
   the wrong theme). */
:root {
  color-scheme: dark;
  --bg: #16161a;
  --panel: #1f1f24;
  /* --well: sits between --bg and --panel, for the sidebar's tab
     content area (lighter than the canvas surround, still darker than
     the sidebar's own header/footer chrome). --well-deep: darker than
     --bg, for the color picker's value row, which wants a stronger,
     more visually distinct sunken well. */
  --well: #18181c;
  --well-deep: #101013;
  --text: #eaeaea;
  --border: #333;
  --accent: #6b6b6b;
  accent-color: var(--accent);
}

:root[data-theme="light"] {
  color-scheme: light;
  --bg: #f5f5f5;
  --panel: #ffffff;
  --well: #f8f8f8;
  --well-deep: #ececec;
  --text: #1a1a1a;
  --border: #ddd;
}

/* Smooths the theme toggle: an element with its own transition (most
   interactive controls; see button, .field input/select, .color-swatch)
   overrides this outright rather than adding to it, since transition is
   a single cascaded property, not a per-item merge, so those keep their
   own faster hover/active feel. This is the fallback for everything
   else, buttons, tabs and inputs would already snap on hover if only
   this was here so the color-related ones are duplicated there. */
* {
  box-sizing: border-box;
  transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease,
    box-shadow 0.2s ease;
}

html, body {
  height: 100%;
}

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  background: var(--bg);
  color: var(--text);
  display: flex;
  height: 100vh;
  overflow: hidden;
}

.main-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.controls {
  width: 300px;
  flex-shrink: 0;
  height: 100%;
  background: var(--panel);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.sidebar-toggle {
  display: none;
  position: fixed;
  top: 12px;
  left: 12px;
  z-index: 30;
  width: 40px;
  height: 40px;
  padding: 0;
  align-items: center;
  justify-content: center;
  margin-top: 0;
  transition: left 0.2s ease;
}

.sidebar-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 24;
}

/* Below this width there's no room for a permanent side-by-side layout,
   so the sidebar becomes a full-height overlay drawer toggled by
   .sidebar-toggle instead of always being on screen. */
@media (max-width: 768px) {
  .sidebar-toggle {
    display: flex;
  }

  .controls {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: min(300px, 85vw);
    height: auto;
    z-index: 25;
    transform: translateX(-100%);
    transition: transform 0.2s ease;
    box-shadow: 2px 0 16px rgba(0, 0, 0, 0.35);
  }

  body.sidebar-open .controls {
    transform: translateX(0);
  }

  /* Slide the toggle (now acting as a close button) out to the right of
     the open drawer instead of leaving it stacked on the drawer's own
     title. */
  body.sidebar-open .sidebar-toggle {
    left: calc(min(300px, 85vw) + 12px);
  }

  body.sidebar-open .sidebar-backdrop {
    display: block;
  }

  .canvas-area {
    padding: 16px;
  }
}

.controls-header {
  flex-shrink: 0;
  padding: 20px 20px 0;
}

.controls-body {
  flex: 1;
  overflow-y: auto;
  padding: 16px 20px 20px;
  background: var(--well);
}

.controls-footer {
  flex-shrink: 0;
  padding: 20px;
  border-top: 1px solid var(--border);
}

.title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 16px;
}

.title-row-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.icon-btn {
  padding: 8px 12px;
}

.icon-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.controls h1 {
  font-size: 16px;
  margin: 0;
}

.controls h1 a {
  color: inherit;
  text-decoration: none;
}

.controls h1 a:hover {
  opacity: 0.8;
}

.title-row button {
  width: auto;
  flex-shrink: 0;
  margin-top: 0;
}

.split-btn {
  display: flex;
  flex-shrink: 0;
}

.split-btn button {
  width: auto;
  margin-top: 0;
}

.split-btn-main {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.split-btn-select {
  width: 30px;
  flex-shrink: 0;
  margin-top: 0;
  padding: 8px 0;
  border: 1px solid var(--border);
  border-radius: 0 6px 6px 0;
  /* Invisible at rest (matches the shared fill), so the only visible
     line at the seam is split-btn-main's own right border, at the same
     1px weight as every other edge. Reappears in accent on this
     control's own hover/focus, independent of its neighbor. */
  border-left-color: transparent;
  background-color: transparent;
  color: var(--text);
  font-size: 13px;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
  /* Pushes the selected option's text off the visible box (the popup
     list itself is unaffected) so only the chevron shows at rest; the
     real value only needs to be visible once the list is open. */
  text-indent: -9999px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23999999' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 15px;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}

/* The darker "well" fill only appears once the dropdown is actually
   open (a native select stays focused while its list is up), rather
   than sitting on permanently and mismatching its other half. */
.split-btn-select:focus {
  background-color: var(--bg);
  border-color: var(--accent);
  outline: none;
}

.split-btn-select:hover {
  background-color: var(--bg);
  border-color: var(--accent);
}

#playBtn.playing,
#playBtn.playing + .split-btn-select {
  background-color: var(--accent);
  color: white;
  border-color: var(--accent);
}

.tabs {
  display: flex;
  gap: 4px;
}

/* No border-radius on the well below (see .controls-body) and no gap
   between a tab and it: the active tab fills with the well's own
   background and drops its bottom border, so its shape reads as
   growing directly out of the content instead of a separate rounded
   panel sitting under a divider line. */
.tab-btn {
  flex: 1;
  width: auto;
  margin-top: 0;
  padding: 8px 4px;
  background: transparent;
  color: var(--text);
  opacity: 0.6;
  border: none;
  border-bottom: 1px solid var(--border);
  border-radius: 6px 6px 0 0;
  font-size: 12px;
}

.tab-btn.active {
  opacity: 1;
  background: var(--well);
  border-bottom-color: transparent;
}

.tab-btn:hover:not(.active) {
  opacity: 0.85;
}

.field {
  margin-bottom: 14px;
}

.section-title {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  opacity: 0.7;
  margin: 20px 0 10px;
  border-top: 1px solid var(--border);
  padding-top: 14px;
}

/* The border/margin above exist to separate a section from whatever
   came before it; a title that opens its panel (Layer A/B's "Fill")
   has nothing above it to separate from. */
.section-title:first-child {
  margin-top: 0;
  border-top: none;
  padding-top: 0;
}

.palette-section {
  margin: 2px 0 14px;
}

.palette-toggle {
  width: 100%;
  margin-top: 0;
  padding: 6px 8px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  font-size: 13px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
}

.palette-toggle:hover {
  border-color: var(--accent);
}

.palette-toggle i {
  font-size: 13px;
  opacity: 0.7;
  transition: transform 0.15s ease;
}

.palette-toggle[aria-expanded="true"] i {
  transform: rotate(180deg);
}

.palette-content {
  margin-top: 8px;
  padding: 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
}

.palette-content .hint {
  margin-top: 0;
}

.preset-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 14px;
}

.preset-chip-row button {
  width: auto;
  flex: 0 0 auto;
  margin-top: 0;
  padding: 5px 10px;
  font-size: 11px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
}

.preset-chip-row .dimension-preset-btn {
  flex: 1;
  text-align: center;
}

.preset-chip-row button:hover {
  border-color: var(--accent);
}

.field label {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 12px;
  margin-bottom: 4px;
  opacity: 0.8;
}

.field label span {
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  min-width: 34px;
  padding: 2px 6px;
  text-align: center;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 4px;
  opacity: 1;
}

.field input[type="text"],
.field input[type="number"],
.field select {
  width: 100%;
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  color: var(--text);
  font-size: 13px;
  transition: border-color 0.15s ease, background-color 0.15s ease, color 0.15s ease;
}

.field input[type="text"]:hover,
.field input[type="number"]:hover,
.field select:hover {
  border-color: var(--accent);
}

/* The native select arrow eats into the right padding without being part
   of the declared padding box, so the text sits visibly closer to the
   right edge than the left. Replace it with a custom chevron and give
   the text equal breathing room on both sides. */
.field select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 28px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23999999' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 8px center;
  background-size: 15px;
}

/* The input's own box is the actual click/drag target, so it's sized
   well past the 4px track drawn inside it (see the track/thumb rules
   below) rather than matching it. Browsers center a shorter track
   pseudo-element vertically within this taller box on their own, and
   the thumb's own centering (its margin-top on WebKit, automatic on
   Firefox) is relative to that track, not this height, so neither
   needs to change to match. */
.field input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 24px;
  margin: 0;
  background: transparent;
  cursor: pointer;
}

.field input[type="range"]::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 2px;
  background: linear-gradient(
    to right,
    var(--accent) 0%,
    var(--accent) calc(var(--pct, 0) * 1%),
    var(--bg) calc(var(--pct, 0) * 1%),
    var(--bg) 100%
  );
  border: 1px solid var(--border);
}

.field input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 14px;
  height: 14px;
  margin-top: -5px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--panel);
  box-shadow: 0 0 0 1px var(--border);
  transition: transform 0.15s ease;
}

.field input[type="range"]:hover::-webkit-slider-thumb {
  transform: scale(1.2);
}

.field input[type="range"]::-moz-range-track {
  height: 4px;
  border-radius: 2px;
  background: var(--bg);
  border: 1px solid var(--border);
}

.field input[type="range"]::-moz-range-progress {
  height: 4px;
  border-radius: 2px;
  background: var(--accent);
}

.field input[type="range"]::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--panel);
  box-shadow: 0 0 0 1px var(--border);
  transition: transform 0.15s ease;
}

.field input[type="range"]:hover::-moz-range-thumb {
  transform: scale(1.2);
}

.slider-wrap {
  position: relative;
  width: 100%;
}

.field-row .slider-wrap {
  flex: 1;
  min-width: 0;
}

.slider-tooltip {
  position: absolute;
  bottom: 100%;
  margin-bottom: 5px;
  transform: translateX(-50%);
  background: #262626;
  color: #ffffff;
  border: 1px solid rgba(255, 255, 255, 0.12);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  padding: 3px 7px;
  border-radius: 5px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.12s ease;
  z-index: 5;
}

.slider-tooltip.visible {
  opacity: 1;
}

.slider-tooltip::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 4px solid transparent;
  border-top-color: #262626;
}

.field-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.field-row input,
.field-row select {
  flex: 1;
  min-width: 0;
}

.lock-btn {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  padding: 0;
  margin-top: 0;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  opacity: 0.55;
}

.lock-btn:hover:not(.locked) {
  opacity: 1;
  border-color: var(--accent);
}

.lock-btn i {
  font-size: 14px;
}

.lock-btn.locked {
  opacity: 1;
  background: var(--accent);
  border-color: var(--accent);
  color: white;
}

.color-row {
  display: flex;
  gap: 10px;
}

.color-row .field {
  flex: 1;
}

.color-input-native {
  display: none;
}

.color-picker {
  position: relative;
  flex: 1;
  min-width: 0;
}

.color-swatch {
  width: 100%;
  height: 32px;
  margin-top: 0;
  padding: 2px;
  display: flex;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--bg);
  color: var(--text);
  transition: border-color 0.15s ease, background-color 0.15s ease, color 0.15s ease;
}

.color-swatch:hover {
  border-color: var(--accent);
}

.color-swatch-fill {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  border-radius: 4px;
  border: 1px solid var(--border);
}

.color-swatch-hex {
  flex: 1;
  min-width: 0;
  text-align: center;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  text-transform: uppercase;
  opacity: 0.85;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.color-popover {
  position: absolute;
  top: 0;
  left: 0;
  width: 220px;
  z-index: 50;
  padding: 12px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
}

.color-sl-square {
  position: relative;
  width: 100%;
  height: 140px;
  border-radius: 6px;
  overflow: hidden;
  border: 1px solid var(--border);
  cursor: crosshair;
  touch-action: none;
}

.color-sl-square canvas {
  display: block;
  width: 100%;
  height: 100%;
}

.color-sl-thumb {
  position: absolute;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 2px solid #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.4);
  transform: translate(-50%, -50%);
  pointer-events: none;
}

.color-hue-strip {
  position: relative;
  width: 100%;
  height: 14px;
  margin-top: 10px;
  border-radius: 7px;
  border: 1px solid var(--border);
  cursor: pointer;
  touch-action: none;
  background: linear-gradient(
    to right,
    hsl(0, 100%, 50%),
    hsl(60, 100%, 50%),
    hsl(120, 100%, 50%),
    hsl(180, 100%, 50%),
    hsl(240, 100%, 50%),
    hsl(300, 100%, 50%),
    hsl(360, 100%, 50%)
  );
}

.color-hue-thumb {
  position: absolute;
  top: 50%;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.4);
  transform: translate(-50%, -50%);
  pointer-events: none;
}

.color-format-tabs {
  display: flex;
  gap: 4px;
  margin-top: 10px;
}

.color-format-btn {
  flex: 1;
  width: auto;
  margin-top: 0;
  padding: 4px;
  font-size: 11px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  opacity: 0.7;
}

.color-format-btn:hover:not(.active) {
  opacity: 1;
  border-color: var(--accent);
}

.color-format-btn.active {
  opacity: 1;
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* Bleeds past the popover's own 12px padding to sit flush against its
   edges, like a sunken well let into the popover rather than a box
   floating inside it. The matching 12px side padding put back on top
   of that negative margin cancels it out for the row's own content,
   so the value text still lines up under the square and hue strip
   above instead of drifting outward with the bleed. The popover's own
   overflow:hidden clips the well's square corners into its rounded
   ones, so this doesn't need to match that radius itself. */
.color-value-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 8px -12px -12px;
  padding: 10px 12px 12px;
  border-top: 1px solid var(--border);
  background: var(--well-deep);
}

.color-value-row[hidden] {
  display: none;
}

.color-hex-prefix {
  font-size: 13px;
  opacity: 0.6;
}

.color-hex-input {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  color: var(--text);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  text-transform: uppercase;
  outline: none;
}

.color-channel {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  font-size: 11px;
  opacity: 0.75;
}

.color-channel input {
  width: 32px;
  min-width: 0;
  border: none;
  background: transparent;
  color: var(--text);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  text-align: center;
  outline: none;
}

/* Chrome/Safari add spinner arrows to number inputs by default; they don't
   fit this compact a field and duplicate the drag/hex ways of changing
   the value, so they're switched off here (Firefox via -moz-appearance
   on the input itself, below). */
.color-channel input::-webkit-outer-spin-button,
.color-channel input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.color-channel input[type="number"] {
  -moz-appearance: textfield;
}

button {
  width: 100%;
  padding: 8px 10px;
  margin-top: 6px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: var(--accent);
  color: white;
  font-size: 13px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  transition: filter 0.15s ease, border-color 0.15s ease, background-color 0.15s ease,
    color 0.15s ease, opacity 0.15s ease, transform 0.08s ease;
}

button:hover:not(:disabled) {
  filter: brightness(1.15);
}

button:active:not(:disabled) {
  filter: brightness(0.92);
  transform: scale(0.98);
}

button i {
  font-size: 15px;
  line-height: 1;
}

button.secondary {
  background: transparent;
  color: var(--text);
  border: 1px solid var(--border);
}

button.secondary:hover:not(:disabled) {
  background: var(--bg);
  border-color: var(--accent);
}

.canvas-area {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px;
  overflow: auto;
}

.site-footer {
  flex-shrink: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 6px;
  padding: 6px 0 14px;
  font-size: 11px;
  color: var(--text);
  opacity: 0.45;
  transition: opacity 0.15s ease;
}

.site-footer:hover {
  opacity: 1;
}

.site-footer a {
  color: inherit;
  text-decoration: none;
}

.site-footer a:hover {
  text-decoration: underline;
}

.site-footer span {
  opacity: 0.7;
}

#preview {
  max-width: 100%;
  max-height: 80vh;
  border: 1px solid var(--border);
  border-radius: 4px;
}

.hint {
  font-size: 11px;
  opacity: 0.6;
  margin-top: 8px;
  margin-bottom: 12px;
}

.button-row {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
}

.button-row > button {
  flex: 1;
  margin-top: 0;
}

.controls-footer .button-row {
  margin-bottom: 0;
}

.preset-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}

.preset-label {
  font-size: 12px;
  font-weight: 600;
}

.preset-status {
  flex: 1;
  font-size: 11px;
  opacity: 0.55;
}

.preset-btn {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  padding: 0;
  margin-top: 0;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
}

.preset-btn i {
  font-size: 14px;
}

.preset-btn:hover:not(:disabled) {
  border-color: var(--accent);
}

.preset-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.ph-spinner-gap {
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* If the Phosphor icon font fails to load, index.html adds this class
   to <html> and every icon falls back to a plain Unicode character
   instead of an empty, unlabeled box. */
html.icon-fallback .ph::before {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI Emoji", "Segoe UI", sans-serif;
}

html.icon-fallback .ph-shuffle::before {
  content: "\1F500\FE0E";
}

html.icon-fallback .ph-lock-simple::before,
html.icon-fallback .ph-lock::before {
  content: "\1F512\FE0E";
}

html.icon-fallback .ph-lock-simple-open::before,
html.icon-fallback .ph-lock-open::before {
  content: "\1F513\FE0E";
}

html.icon-fallback .ph-play::before {
  content: "\25B6\FE0E";
}

html.icon-fallback .ph-pause::before {
  content: "\23F8\FE0E";
}

html.icon-fallback .ph-caret-down::before {
  content: "\2304";
}

html.icon-fallback .ph-floppy-disk::before {
  content: "\1F4BE\FE0E";
}

html.icon-fallback .ph-folder-open::before {
  content: "\1F4C2\FE0E";
}

html.icon-fallback .ph-download-simple::before {
  content: "\2B07\FE0E";
}

html.icon-fallback .ph-spinner-gap::before {
  content: "\21BB";
}

html.icon-fallback .ph-arrow-counter-clockwise::before {
  content: "\21BA";
}

html.icon-fallback .ph-link::before {
  content: "\1F517\FE0E";
}

html.icon-fallback .ph-check::before {
  content: "\2713\FE0E";
}

html.icon-fallback .ph-sun::before {
  content: "\2600\FE0E";
}

html.icon-fallback .ph-moon::before {
  content: "\1F319\FE0E";
}

html.icon-fallback .ph-list::before {
  content: "\2630";
}

html.icon-fallback .ph-x::before {
  content: "\2715";
}

button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}
