/* sam — shared stylesheet
   Lives at the site root on purpose: url() below resolves relative to THIS
   file, not to the page linking it, so pages/ and / share one set of paths. */

/* Must stay the first rule in the file, or browsers ignore it. Only the
   weights the site uses: 300 for text, 400 for window titles, 700 for the
   files in the tree whose pages are open. */
@import url("https://fonts.googleapis.com/css2?family=Martian+Mono:wght@300;400;700&display=swap");

:root {
  --bg: #0004ff;
  --panel: #dffbdfdf;
  --panel-solid: #dffbdf;   /* same colour, no transparency — for floating windows */
  --text: #000000;
  --muted: #313131;
  --folder: #facc15;
  --link: #2b2a2a;
  --border: #212121;
  --vine: #138d29;
  --autumn: hsl(0, 81%, 45%);
  --desk: #ffffff;          /* homepage tree window */
  --line: #808080;          /* tree branch dots, quote bars */
  --titletext-dim: #6b6b6b; /* title text on windows behind the front one */
  --shadow: 2px 2px 0 var(--border);   /* hard shadow: tree boxes, and the front window */
  --desktop-bg: linear-gradient(to top, #0030ff, #dedede);   /* page background: blue up to light grey.
                            colour.js overrides it (keep in step with DEFAULT there) */
}

/* The background colour or gradient lives on <html>, behind <body>, which
   carries only a visitor's own tiled image, if they've added one — so
   changing the colour never touches the image's (possibly huge) style rule.
   "fixed" makes a gradient span the screen rather than the whole page. */
html {
  min-height: 100%;
  background: var(--desktop-bg) fixed;
}

body {
  margin: 0;
  min-height: 100vh;
  display: grid;
  place-items: start center;
  align-content: start;   /* stack the tree boxes at the top, not spread down the page */
  gap: 24px;
  background-repeat: repeat;   /* a visitor's own tile image, if any, is set by colour.js */
  color: var(--text);
  font-family: "Martian Mono", "Courier New", Courier, monospace;
  font-weight: 300;
  font-size: 13px;
  padding: 32px 16px;
}

.window {
  box-sizing: border-box;   /* padding + border count inside the width */
  width: min(760px, 100%);
  background: var(--desk);
  border: 1px solid var(--border);
  border-radius: 4px;
  box-shadow: var(--shadow);
  padding: 18px 22px;
}

/* The folder-tree boxes on the homepage hug their contents, growing as
   folders open and shrinking back as they close. */
.window:has(> ul.tree) {
  width: fit-content;
  min-width: 11rem;
  max-width: 100%;
  /* left edge stays where the old 760px-wide box's left edge was */
  justify-self: start;
  padding-right: 32px;   /* matches the left edge to the branch bars: 22px padding + 10px indent */
  margin-left: calc((100% - min(760px, 100%)) / 2);
}

/* Pale variant, used by the interior pages */
.window.panel {
  background: var(--panel);
}

h1 {
  margin: 0;
  font-size: 1.05em;
  color: var(--muted);
  font-weight: normal;
}

.help {
  margin: 0.85rem 0 1rem;
  padding: 0.7rem;
  border: 1px dashed var(--border);
  font-size: 0.92em;
  color: var(--muted);
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.help strong {
  color: var(--text);
  font-weight: normal;
}

a {
  color: var(--link);
  text-decoration: none;
}

/* Old-OS selection look: inverted colours, hard edges. */
a:hover {
  background: var(--text);
  color: #ffffff;
}

/* Browsers give <code> their own modern system font; keep the page's. */
code {
  font: inherit;
}

/* ---- file tree (homepage) ---- */

ul.tree,
ul.tree ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Every row is exactly 24px tall: the branch ticks below sit at a fixed
   offset from the top of the row. */
.tree li {
  line-height: 24px;
}

.folder-btn {
  all: unset;
  cursor: pointer;
  color: var(--text);
}

/* Folder icon states: resting -> hover -> pressed, and selected while open.
   Equal specificity throughout, so source order sets priority: an open
   folder stays selected on hover, and pressed wins while the click is down. */
.folder-icon {
  display: inline-block;
  width: 20px;
  height: 20px;
  vertical-align: -4px;
  margin-right: 0.35rem;
  background: url("assets/folder.png") center / contain no-repeat;
}

.folder-btn:hover .folder-icon,
.folder-btn:focus-visible .folder-icon {
  background-image: url("assets/folder-hover.png");
}

.folder-btn[aria-expanded="true"] .folder-icon {
  background-image: url("assets/folder-selected.png");
}

.folder-btn:active .folder-icon {
  background-image: url("assets/folder-pressed.png");
}

/* Fetch the other states up front so the first hover/click doesn't blink. */
.tree::after {
  content: url("assets/folder-hover.png") url("assets/folder-pressed.png")
           url("assets/folder-selected.png");
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
  visibility: hidden;
}

/* Files whose page is open in a window (set by windows.js). */
.tree a.is-open {
  font-weight: 700;
}

/* Placeholder row inside a folder with nothing in it yet. */
.tree .empty {
  color: var(--muted);
  font-style: italic;
}

/* Nested lists hang off the middle of their parent's folder icon. */
.tree .children {
  display: none;
  margin-left: 9px;
}

.tree .children.open {
  display: block;
}

.tree .children > li {
  position: relative;
  padding-left: 24px;
}

/* Trunk: each child draws its own stretch of the vertical line, so the
   line runs unbroken past any expanded sub-folder above it. */
.tree .children > li::before {
  content: "";
  position: absolute;
  left: 1px;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--line);
}

/* Branch: horizontal tick from the trunk into each item. */
.tree .children > li::after {
  content: "";
  position: absolute;
  left: 1px;
  top: 12px;
  width: 19px;
  height: 1px;
  background: var(--line);
}

/* Last child: trunk stops at its own branch, making the corner. */
.tree .children > li:last-child::before {
  bottom: auto;
  height: 13px;
}

/* ---- interior pages ---- */

.backlink {
  display: inline-block;
  margin-bottom: 0.9rem;
  font-size: 0.92em;
  color: var(--muted);
}

.content {
  font-size: 1em;
  line-height: 1.65;
}

.content h2 {
  font-size: 1em;
  font-weight: normal;
  margin: 1.4rem 0 0.5rem;
  padding-bottom: 0.3rem;
  border-bottom: 1px dashed var(--border);
}

.content h2:first-child {
  margin-top: 0;
}

.content p {
  margin: 0 0 0.9rem;
}

.content ul {
  margin: 0 0 0.9rem;
  padding-left: 1.2rem;
}

.content li {
  margin: 0.3rem 0;
}

/* Pictures and videos shrink to fit their window or page. */
.content img,
.content video {
  display: block;
  max-width: 100%;
  height: auto;
}

/* Tall (portrait) videos: as wide as fits — the window, 360px, or
   whatever width keeps even a 9:16 video's height within the screen with
   room for a line of text underneath. The height follows the video's own
   shape (from its width and height attributes), so 3:4 fits as well as 9:16. */
.content video.portrait {
  width: min(100%, 360px, calc((100vh - 180px) * 9 / 16));
  height: auto;
  margin: 0 auto;
}

/* A little space between a picture or video and the text under it. */
.content img + p,
.content video + p {
  margin-top: 0.8rem;
}

/* Embedded videos (YouTube, Vimeo...) fill the width at 16:9. */
.content iframe:not(.guestbook-frame) {
  display: block;
  box-sizing: border-box;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--border);
}

.content blockquote {
  margin: 0 0 0.9rem;
  padding: 0.5rem 0.8rem;
  background: repeating-linear-gradient(to bottom, var(--line) 0 3px, transparent 3px 6px)
    left top / 3px 100% no-repeat;
  color: var(--muted);
}

.meta {
  font-size: 0.82em;
  color: var(--muted);
  margin: 0 0 1rem;
}

.entry + .entry {
  margin-top: 1.6rem;
  padding-top: 1.2rem;
  border-top: 1px dashed var(--border);
}

/* ---- embedded guestbook ---- */

.guestbook-frame {
  display: block;
  width: 100%;
  height: 640px;
  border: 1px solid var(--border);
  background: #ffffff;
}

.frame-fallback {
  font-size: 0.82em;
  color: var(--muted);
  margin: 0.6rem 0 0;
}

/* ---- floating page windows (homepage, see windows.js) ---- */

/* Two looks, picked by windows.js from what the page holds:
   - a window (videos, pictures, the guestbook, paint): white, with a
     pastel title bar;
   - a sticky note (pages that are only text, class "note"): all pastel,
     with a slightly darker strip across the top instead of a title bar.
   Only the front window (class "active") gets the hard shadow; notes
   behind it also fade their text. --win-bg, --note-bg and --note-strip are
   one random pastel per window, set by windows.js. */

.win {
  position: fixed;
  display: flex;
  flex-direction: column;
  min-width: 220px;
  background: var(--desk);
  border: 1px solid var(--border);
  border-radius: 4px;
  overflow: hidden;   /* keeps the title bar inside the rounded corners */
  outline: none;
  box-shadow: 0 0 0 var(--border);   /* hidden under the window, so it can grow out smoothly */
  transition: transform 0.12s ease-out, box-shadow 0.12s ease-out;
}

/* The front window lifts up and to the left by the shadow's size, so the
   shadow lands exactly where the window was sitting: the window pops out
   of its shadow, rather than the shadow growing out of the window.
   windows.js reads positions from style.left/top, which leave this out. */
.win.active {
  transform: translate(-2px, -2px);
  box-shadow: var(--shadow);
}

@media (prefers-reduced-motion: reduce) {
  .win {
    transition: none;
  }
}

.win-titlebar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 6px 5px 12px;
  background: var(--win-bg, var(--panel-solid));
  color: var(--text);
  border-bottom: 1px solid var(--border);
  font-size: 12px;
  font-weight: 400;
  cursor: grab;
  user-select: none;
  touch-action: none;
}

.win-gesture .win-titlebar {
  cursor: grabbing;
}

/* Windows behind the front one dim their title. */
.win:not(.active):not(.note) .win-titlebar {
  color: var(--titletext-dim);
  font-weight: 300;
}

.win-title {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.win-close {
  all: unset;
  width: 1.5em;
  line-height: 1.35;
  text-align: center;
  cursor: pointer;
  font-family: Georgia, serif;
  font-style: italic;
  font-weight: 400;
  color: var(--text);
  background: var(--desk);
  border: 1px solid var(--border);
  border-radius: 2px;
}

.win.active .win-close {
  font-weight: 700;
}

.win-close:hover,
.win-close:focus-visible {
  background: var(--autumn);
  color: #ffffff;
}

.win-body {
  flex: 1;
  overflow: auto;
  padding: 18px 22px;
  line-height: 1.65;
}

/* ---- sticky notes ---- */

.win.note {
  min-height: 200px;
  background: var(--note-bg, var(--panel-solid));
}

.win.note .win-titlebar {
  padding: 8px 8px 8px 14px;
  background: var(--note-strip, var(--panel-solid));
  border-bottom: none;
  color: #3d3d3d;
  font-size: 11px;
  font-weight: 300;
}

.win.note .win-close {
  background: transparent;
  border-color: transparent;
}

.win.note .win-close:hover,
.win.note .win-close:focus-visible {
  background: var(--autumn);
  border-color: var(--border);
}

.win.note .win-body {
  padding: 14px 16px 20px;
  line-height: 1.7;
}

/* Notes behind the front window fade everything but the paper. */
.win.note:not(.active) .win-title,
.win.note:not(.active) .win-close,
.win.note:not(.active) .win-body {
  opacity: 0.5;
}

/* Once the visitor resizes a window, its picture or video fills the width
   (no 360px cap on portrait videos, no stopping at an image's own size), so
   the window can keep the picture's shape at any size (see windows.js). */
.win[data-user-sized] .win-body img,
.win[data-user-sized] .win-body video {
  width: 100%;
  max-width: none;
}

/* Resize by dragging the bottom-right corner: no drawn grip, just the
   cursor change when the pointer gets there. */
.win-resize {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 15px;
  height: 15px;
  cursor: nwse-resize;
  touch-action: none;
}

/* Mid-drag: stop text selection, and stop iframes stealing the pointer. */
.win-gesture {
  user-select: none;
}

.win-gesture iframe {
  pointer-events: none;
}

/* ---- background theme controls (pages/paint.html, see colour.js) ---- */

/* The UA's [hidden] rule loses to "all: unset" on buttons; make it win. */
[hidden] {
  display: none !important;
}

.cp-wheel,
.cp-value {
  display: block;
  cursor: crosshair;
  touch-action: none;
  image-rendering: pixelated;   /* hard pixels, no smoothing */
}

.cp-value {
  border: 1px solid var(--border);
}

.cp-wheel:focus-visible,
.cp-value:focus-visible {
  outline: 1px dotted var(--text);
  outline-offset: 2px;
}

.cp-btn {
  all: unset;
  cursor: pointer;
  font-size: 0.8rem;
  padding: 0 0.4rem;
  background: var(--desk);
  border: 1px solid var(--border);
}

.cp-btn:hover,
.cp-btn:focus-visible {
  background: var(--text);
  color: #ffffff;
}

.cp-note {
  margin: 0;
  font-size: 0.8rem;
  color: var(--muted);
}

/* ---- paint tool (pages/paint.html, see paint.js) ---- */

/* The selected tool stays inverted. */
.cp-btn[aria-pressed="true"] {
  background: var(--text);
  color: #ffffff;
}

/* Two drawings. "over" sits over the whole site; "under" sits just above
   the background, beneath every window. Each only takes the mouse while the
   paint tools are open and it's the one being drawn on; the tools' own
   window always stays above both. */
.paint-layer {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 2147483000;
  pointer-events: none;
  image-rendering: pixelated;
}

.paint-layer-under {
  z-index: 0;
}

/* Lift the page's own boxes (the homepage tree and tools, an interior
   page opened on its own) above the "under" drawing. Floating windows
   already sit higher (windows.js gives them z-index 11 and up). */
.window {
  position: relative;
  z-index: 1;
}

.paint-layer.painting {
  pointer-events: auto;
  cursor: crosshair;
}

.win.win-paint {
  z-index: 2147483001 !important;   /* beats the inline z-index windows.js sets */
}

main.win-paint {                    /* paint.html opened on its own */
  position: relative;
  z-index: 2147483001;
}


/* Bottom-centre bar: "clear drawing" (paint.js) and "clear background"
   (colour.js), each shown only when there's something to clear, and centred
   together. Sits above the drawing, so it works even while painting. */
.bottom-bar {
  position: fixed;
  left: 50%;
  bottom: 12px;
  transform: translateX(-50%);
  z-index: 2147483002;
  display: flex;
  gap: 6px;
  white-space: nowrap;
}

/* Same order whichever script adds its button first. */
.clear-drawing-btn    { order: 1; }
.clear-background-btn { order: 2; }

/* ---- paint + background tool layout (pages/paint.html) ---- */

/* Two equal group boxes, side by side when there's room, stacked when not. */
.tool-sections {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 12px;
  align-items: stretch;
}

/* Old-OS "group box": a 1px frame with its title set into the top edge. */
.tool-group {
  display: grid;
  gap: 8px;
  align-content: start;
  min-width: 0;
  margin: 0;
  padding: 10px 12px 12px;
  border: 1px solid var(--border);
}

.tool-group > legend {
  padding: 0 4px;
  font-size: 0.9rem;
}

/* Buttons on a grid, every button in a row the same width. */
.btn-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 4px;
}

.btn-grid.cols-2 {
  grid-template-columns: repeat(2, 1fr);
}

.btn-grid.cols-3 {
  grid-template-columns: repeat(3, 1fr);
}

.btn-grid .cp-btn {
  display: block;
  padding: 2px 0;
  text-align: center;
}

/* Wheel with its brightness bar underneath and a colour square beside it —
   laid out the same way in both boxes. */
.colour-row {
  display: grid;
  grid-template-columns: 122px 1fr;
  column-gap: 12px;
  row-gap: 6px;
  align-items: start;
}

.colour-row .cp-wheel { grid-area: 1 / 1; margin-left: 1px; }
.colour-row .cp-value { grid-area: 2 / 1; }
.colour-row .swatch   { grid-area: 1 / 2; }

.swatch {
  display: block;
  width: 40px;
  height: 40px;
  border: 1px solid var(--border);
}

/* The paint size slider, with the tool's mark at its real size beside it
   (drawn by paint.js) on a checkerboard, so even white paint shows. */
.size-row {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 10px;
}

.pt-preview {
  display: block;
  width: 64px;
  height: 64px;
  border: 1px solid var(--border);
  image-rendering: pixelated;
  background: repeating-conic-gradient(#e4e4e4 0 25%, #ffffff 0 50%) 0 0 / 8px 8px;
}

/* A label, a slider and its value on one line. */
.slider-row {
  display: grid;
  grid-template-columns: auto 1fr 3.5em;
  align-items: center;
  gap: 8px;
  font-size: 0.8rem;
}

.slider-row output {
  text-align: right;
}

/* Sliders in the old-OS style: a thin boxed track and a square handle. */
.cp-range {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 16px;
  margin: 0;
  background: transparent;
  cursor: pointer;
}

.cp-range::-webkit-slider-runnable-track {
  height: 6px;
  background: var(--desk);
  border: 1px solid var(--border);
}

.cp-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  box-sizing: border-box;
  width: 10px;
  height: 16px;
  margin-top: -6px;   /* centre the handle on the track */
  background: var(--desk);
  border: 1px solid var(--border);
  border-radius: 0;
}

.cp-range::-moz-range-track {
  height: 6px;
  background: var(--desk);
  border: 1px solid var(--border);
}

.cp-range::-moz-range-thumb {
  box-sizing: border-box;
  width: 10px;
  height: 16px;
  background: var(--desk);
  border: 1px solid var(--border);
  border-radius: 0;
}

.cp-range:focus-visible {
  outline: 1px dotted var(--text);
  outline-offset: 2px;
}

/* A small colour chip inside a button: the gradient's top and bottom colours. */
.chip {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: 6px;
  vertical-align: -1px;
  border: 1px solid var(--border);
}

.cp-btn[aria-pressed="true"] .chip {
  border-color: #ffffff;
}

/* "remove image" gets a row of its own under "upload image…" and "reset". */
.btn-grid.cols-2 .cp-remove-image {
  grid-column: 1 / -1;
}

