/* ascii-anima mapper page · layout and controls; the tokens are in tokens.css.
   The mapper shares the gallery's type and design tokens: body.page takes the
   standard scale from tokens.css, Space Grotesk names things, Space Mono
   stays for labels and values. The wider scale needs a wider inspector. */
/* tokens live in tokens.css (linked before this file) */
*{box-sizing:border-box}
[hidden]{display:none !important}
html,body{margin:0}
body{
	background:var(--bg); color:var(--tx); font-family:var(--mono);
	font-size:var(--fs-base); line-height:1.5; -webkit-font-smoothing:antialiased;
}
:focus-visible{outline:var(--bw-2) solid var(--am); outline-offset:2px}
/* scrollbars in the theme: square, dark, amber on hover.
   Chrome/Safari/Edge take the ::-webkit-scrollbar rules; Firefox has no
   such selector and takes scrollbar-color instead (setting both would make
   Chrome ignore the square ones) */
::-webkit-scrollbar{width:10px; height:10px}
::-webkit-scrollbar-track, ::-webkit-scrollbar-corner{background:var(--bg)}
::-webkit-scrollbar-thumb{background:var(--line2); border:var(--bw-3) solid var(--bg); border-radius:0}
::-webkit-scrollbar-thumb:hover{background:var(--am)}
@supports not selector(::-webkit-scrollbar){
	*{scrollbar-color:var(--line2) var(--bg); scrollbar-width:thin}
}
a{color:var(--mut)}
a:hover{color:var(--am)}

/* ── shell: bar on top, stage left, inspector right, one screen ── */
.app{display:flex; flex-direction:column; height:100vh; overflow:hidden}
.bar{
	position:sticky; top:0; z-index:5; height:var(--bar); flex:none;
	display:flex; align-items:center; gap:var(--s-6); padding:0 var(--s-7);
	background:var(--bg); border-bottom:var(--bw) solid var(--line);
}
.bar-link{font-size:var(--fs-sm); letter-spacing:var(--ls-label); text-transform:uppercase}
/* the ASCII ANIMA wordmark, as on the gallery (Space Grotesk 700, tight), set small */
h1{font-family:var(--display); font-size:var(--fs-h); font-weight:700; letter-spacing:var(--ls-tight); line-height:1; margin:0; white-space:nowrap}
/* "by" + the creativetech.wtf pixel wordmark, 12px so crispEdges lands on whole pixels */
.bar > .by{margin-left:auto}
.by{display:inline-flex; align-items:center; gap:var(--s-3); font-size:var(--fs-xs); letter-spacing:var(--ls-micro); text-transform:uppercase; color:var(--mut); text-decoration:none; white-space:nowrap}
.by:hover{color:var(--am)}
.by .wm{display:block; height:8px; width:auto} /* small, on the bar's far right */
.vh{position:absolute; width:1px; height:1px; margin:-1px; padding:0; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0}
h1 a{color:var(--tx); text-decoration:none}
h1 a:hover{color:var(--am)}

.work{
	flex:1; display:grid; grid-template-columns:minmax(0,1fr) var(--inspector-w); grid-template-rows:minmax(0,1fr);
	min-height:0;
}
.stage-col{display:flex; flex-direction:column; min-height:0; min-width:0; padding:var(--s-7); overflow:hidden}
.stage-fit{flex:1; min-height:0; display:flex; align-items:center; justify-content:center; overflow:hidden}
/* the stage's width is set from script so its HEIGHT fits the column */
/* the preview's own box: its width is the stage size (fit, a preset, or
   dragged by the grip); the stage inside fills it */
.stage-box{position:relative; flex:none}
#stage, #revealStage{width:100%; position:relative}
/* the grip's 14px square, half of it hanging off the corner, is a one-off */
.grip{position:absolute; right:-7px; bottom:-7px; width:14px; height:14px; z-index:3;
	background:var(--am); border:var(--bw-3) solid var(--bg); cursor:nwse-resize; touch-action:none}
.grip:hover, .grip.on{background:var(--tx)}
/* the player's draw rate, beside the size (mapper/stage.js watchFps) */
.fps-out{font-size:var(--fs-sm); color:var(--mut); font-variant-numeric:tabular-nums; min-width:52px; text-align:right}
.fps-out.hot{color:var(--warn)}
/* the built-in source's credit, under the preview and as wide as it */
.stage-credit{position:absolute; left:0; right:0; top:100%; margin:12px 0 0; font-size:var(--fs-sm);
	color:var(--mut); text-align:center}
.stage-credit a{color:var(--am)}
.sizer{display:flex; align-items:center; gap:var(--s-4); margin-left:auto} /* pinned right, whether the stats line or the bake bar is showing */
.size-out{font-size:var(--fs-sm); color:var(--mut); font-variant-numeric:tabular-nums; min-width:96px}
#revealStage{background:var(--bg)}
/* touch-action stays default so swipes over the canvas scroll the page;
   the callout/select suppression is scoped to the canvas only */
#stage canvas{-webkit-touch-callout:none}
.stage-foot{flex:none; display:flex; align-items:center; gap:var(--s-6); flex-wrap:wrap;
	padding-top:var(--s-5); margin-top:var(--s-5); border-top:var(--bw) solid var(--line)}
.stats{margin:0; font-size:var(--fs-sm); color:var(--tx); flex:1; min-width:180px}
/* the clip bake's loading bar: square, amber, frames counted beside it.
   The fill's 1px insets and its 2px are the track's border, both sides;
   the width mapper/edits.js bakeProgress() sets takes the same 2px off */
.bake{display:flex; align-items:center; gap:var(--s-4); font-size:var(--fs-sm); color:var(--tx)}
.bake-label{color:var(--am)}
.bake-track{position:relative; width:220px; height:10px; border:var(--bw) solid var(--line2); background:var(--bg)}
.bake-fill{position:absolute; left:1px; top:1px; bottom:1px; width:0; max-width:calc(100% - 2px); background:var(--am)}
.bake-count{color:var(--mut); font-variant-numeric:tabular-nums; min-width:64px}
.stage-btns{display:flex; gap:var(--s-3)}

.inspector{border-left:var(--bw) solid var(--line); overflow:auto; min-height:0; background:var(--bg)}
.panel-foot{display:flex; gap:var(--s-4); padding:var(--s-8) var(--s-7) 28px}
.panel-foot .btn{flex:1}

/* ── sections ── */
.sec{border-bottom:var(--bw) solid var(--line)}
.sec > summary{
	list-style:none; cursor:pointer; padding:var(--s-5) var(--s-7); user-select:none;
	font-size:var(--fs-sm); letter-spacing:var(--ls-head); text-transform:uppercase; color:var(--tx);
	display:flex; align-items:center; gap:var(--s-4);
}
.sec > summary::-webkit-details-marker{display:none}
.sec > summary::after{content:'+'; margin-left:auto; color:var(--dim); font-size:var(--fs-lg)}
.sec[open] > summary::after{content:'−'}
.sec > summary:hover{color:var(--am)}
.sec .n{color:var(--am)}
.sec-body{padding:var(--s-1) var(--s-7) 26px}
.note{font-size:var(--fs-sm); color:var(--mut); margin:0 0 var(--s-5); line-height:1.6}
.note b{color:var(--tx); font-weight:400}

/* ── controls ── */
/* room to breathe: every control gets air around it */
.ctl{margin:0 0 var(--s-7)}
.ctl:last-child{margin-bottom:0}
.ctl > label{display:flex; justify-content:space-between; gap:var(--s-3); font-size:var(--fs-xs);
	letter-spacing:var(--ls-label); text-transform:uppercase; color:var(--mut); margin-bottom:var(--s-2)}
.ctl output{color:var(--tx)}
.pair{display:grid; grid-template-columns:1fr 1fr; gap:var(--s-5) var(--s-8); margin-bottom:var(--s-7)}
.pair .ctl{margin:0}
.pair .ctl-wide{grid-column:1 / -1}
/* square everything: round browser sliders and dots do not fit the
   grid-of-characters look. --p is the filled share,
   kept in step by mapper/edits.js so the amber runs up to the thumb.
   The 2px track, the 12px thumb and its -5px lift go together (one-offs) */
input[type=range]{-webkit-appearance:none; appearance:none; width:100%; height:var(--h-slider); margin:0;
	background:transparent; cursor:pointer}
input[type=range]::-webkit-slider-runnable-track{height:2px;
	background:linear-gradient(to right, var(--am) var(--p, 50%), var(--line2) var(--p, 50%))}
input[type=range]::-moz-range-track{height:2px; background:var(--line2)}
input[type=range]::-moz-range-progress{height:2px; background:var(--am)}
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none; appearance:none; width:12px; height:12px;
	margin-top:-5px; background:var(--am); border:0; border-radius:0}
input[type=range]::-moz-range-thumb{width:12px; height:12px; background:var(--am); border:0; border-radius:0}
input[type=range]:hover::-webkit-slider-thumb{background:var(--tx)}
input[type=range]:hover::-moz-range-thumb{background:var(--tx)}
/* past its safe range (data-hot, mapper/edits.js fillRange): the fill and
   thumb go red, so the cost of the setting is visible before it is felt */
input[type=range].hot::-webkit-slider-runnable-track{
	background:linear-gradient(to right, var(--warn) var(--p, 50%), var(--line2) var(--p, 50%))}
input[type=range].hot::-moz-range-progress{background:var(--warn)}
input[type=range].hot::-webkit-slider-thumb{background:var(--warn)}
input[type=range].hot::-moz-range-thumb{background:var(--warn)}
.ctl:has(input.hot) output{color:var(--warn)}
select{width:100%; background:var(--bg); color:var(--tx); border:var(--bw) solid var(--line2);
	font:inherit; font-size:var(--fs-md); padding:var(--s-2) var(--s-3); min-height:var(--h-ctl)}
.checks{display:flex; gap:var(--s-8); flex-wrap:wrap; margin:calc(var(--s-2) * -1) 0 var(--s-7)}
.check{display:flex; align-items:center; gap:var(--s-3); font-size:var(--fs-sm); color:var(--mut); cursor:pointer; min-height:var(--h-row)}
/* the 14px box is a one-off */
.check input{-webkit-appearance:none; appearance:none; width:14px; height:14px; margin:0; flex:none;
	border:var(--bw) solid var(--line2); border-radius:0; background:var(--bg); cursor:pointer}
.check input:checked{background:var(--am); border-color:var(--am); box-shadow:inset 0 0 0 var(--bw-3) var(--bg)}
.check:hover input{border-color:var(--am)}
.check:hover{color:var(--tx)}

.btn, .seg button, .seg .filebtn{
	display:inline-flex; align-items:center; justify-content:center; gap:var(--s-2);
	min-height:var(--h-ctl); padding:var(--s-2) var(--s-5); background:var(--bg); color:var(--tx);
	border:var(--bw) solid var(--line2); font:inherit; font-size:var(--fs-sm); letter-spacing:var(--ls-btn);
	text-transform:lowercase; cursor:pointer; white-space:nowrap;
}
.btn:hover, .seg button:hover, .seg .filebtn:hover{border-color:var(--am); color:var(--am)}
.btn-primary{background:var(--am); color:var(--bg); border-color:var(--am)}
.btn-primary:hover{background:var(--bg); color:var(--am)}
.btn-sm{min-height:var(--h-ctl-sm); padding:var(--s-1) var(--s-4)}
.btn:disabled{opacity:.35; cursor:default; border-color:var(--line2); color:var(--tx)}
.filebtn{position:relative}
.filebtn input{position:absolute; width:1px; height:1px; opacity:0; overflow:hidden}
.filebtn:focus-within{outline:var(--bw-2) solid var(--am); outline-offset:2px}

/* segmented: one row of joined buttons, the pressed one lit */
.seg{display:inline-flex}
.seg > *{margin-left:calc(var(--bw) * -1)}
.seg > *:first-child{margin-left:0}
.seg button[aria-pressed="true"]{border-color:var(--am); color:var(--am); background:var(--am-soft); position:relative; z-index:1}
.seg-sm button, .seg-sm .filebtn{min-height:var(--h-ctl-sm); padding:var(--s-1) var(--s-4)}
.seg-wrap{display:flex; flex-wrap:wrap}
.seg-wrap > *{flex:1 1 auto}
.presetrow{margin-bottom:var(--s-7)}

/* the 64px thumbnail and the 24px under the source are one-offs */
.source{display:flex; gap:var(--s-5); align-items:flex-start; margin-bottom:24px}
.source-actions{display:flex; gap:var(--s-3); margin-bottom:var(--s-5)}
.source-actions .btn{flex:1}
.mode-row{padding:var(--s-7) var(--s-7) var(--s-5); margin:0; border-bottom:var(--bw) solid var(--line)}
.source img{width:64px; height:64px; object-fit:cover; border:var(--bw) solid var(--line); display:block; flex:none}
.source-side{min-width:0; display:flex; flex-direction:column; gap:var(--s-3)}
.source p{margin:0; font-size:var(--fs-sm); color:var(--mut); line-height:1.5; word-break:break-word}
.source p a{color:var(--am)}

/* ── the tone bar ── */
/* 11px side padding (about half a handle, so the end handles stay in the
   column), the bar's 2px margin and the handles' 3px top are one-offs */
.tone{position:relative; user-select:none; margin:var(--s-4) 0 var(--s-5); padding:0 11px}
.tone-row{position:relative; height:var(--h-row); cursor:copy}
.tone-hist{display:block; width:100%; height:var(--h-hist); margin-bottom:var(--s-3)}
.tone-bar{display:block; width:100%; height:var(--h-bar); margin:2px 0; border:var(--bw) solid var(--line2); background:var(--bg2)}
.th{position:absolute; top:3px; width:var(--handle); height:var(--handle); transform:translateX(-50%); padding:0;
	display:flex; align-items:center; justify-content:center; font:inherit; font-size:var(--fs-md); line-height:1;
	background:var(--bg); color:var(--tx); border:var(--bw) solid var(--line2); cursor:ew-resize; touch-action:none}
.th:hover{border-color:var(--am)}
.th[aria-pressed="true"]{border-color:var(--am); color:var(--am); z-index:2}
.tone-cols .th{border-width:var(--bw-2)}
.tone-cols .th[aria-pressed="true"]{outline:var(--bw) solid var(--am); outline-offset:1px}
/* a character being edited in place: the handle becomes a one-glyph field */
input.th{border-color:var(--am); color:var(--am); text-align:center; cursor:text; outline:none; z-index:3}
/* ── the colour picker popover (mapper/picker.js), square and in the tokens ── */
.picker{position:fixed; z-index:20; display:flex; flex-direction:column; gap:var(--s-3); padding:var(--s-3);
	background:var(--bg); border:var(--bw) solid var(--line2); box-shadow:0 12px 32px #00000080}
.picker-sq, .picker-hue{display:block; width:196px; cursor:crosshair; touch-action:none; border:var(--bw) solid var(--line)}
.picker-sq{height:132px}
.picker-hue{height:12px}
.picker-row{display:flex; align-items:center; gap:var(--s-3)}
.picker-preview{flex:none; width:var(--h-ctl-sm); height:var(--h-ctl-sm); border:var(--bw) solid var(--line2)}
.picker-hex{flex:1; min-width:0; min-height:var(--h-ctl-sm); padding:0 var(--s-3); background:var(--bg2); color:var(--tx);
	border:var(--bw) solid var(--line2); font:inherit; font-size:var(--fs-md); letter-spacing:var(--ls-btn); text-transform:lowercase}
.picker-hex:focus{outline:none; border-color:var(--am)}
.picker-swatches{display:grid; grid-template-columns:repeat(8, 1fr); gap:var(--s-1)}
.picker-swatch{aspect-ratio:1; padding:0; border:var(--bw) solid var(--line2); cursor:pointer}
.picker-swatch:hover{border-color:var(--am)}
.picker-swatch[aria-pressed="true"]{outline:var(--bw) solid var(--am); outline-offset:1px}
.tone-tools{display:flex; align-items:center; gap:var(--s-5); margin-top:var(--s-1)}
.tone-lens{margin:calc(var(--s-2) * -1) 0 18px}
.checks-top{margin:calc(var(--s-3) * -1) 0 var(--s-7)}
.tone-tools select{flex:1}

/* ── the curve editor ── */
.curve{margin:0 0 var(--s-6)}
.curve-head{display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--s-3)}
.curve-title{font-size:var(--fs-xs); letter-spacing:var(--ls-label); text-transform:uppercase; color:var(--mut)}
#curveCanvas{display:block; width:100%; height:var(--h-curve); background:var(--bg2);
	border:var(--bw) solid var(--line); touch-action:none; cursor:crosshair}
#curveCanvas:focus-visible{outline:var(--bw-2) solid var(--am); outline-offset:1px}
.curve-readout{margin:var(--s-2) 0 var(--s-4); font-size:var(--fs-xs); color:var(--dim); min-height:15px; letter-spacing:var(--ls-note)}
.curve-readout b{color:var(--am); font-weight:400}
.curve-tools{display:flex; gap:var(--s-3); flex-wrap:wrap; align-items:center}
.curve-tools .seg{flex:1 1 100%}
.btn-icon{min-width:var(--h-ctl-sm); padding:var(--s-1) var(--s-3); font-size:var(--fs-lg); line-height:1}


/* ── narrow: the gate asks for a desktop ──
   900px is not a token: a custom property cannot be used in a media query.
   mapper/stage.js fitStage() matches the same 900px. The stacked layout
   rules below stay so the page is still usable if someone dismisses nothing
   and scrolls, but the gate covers it. */
.gate{display:none}
@media (max-width:900px){
	.gate{position:fixed; inset:0; z-index:50; display:flex; flex-direction:column; justify-content:center;
		gap:var(--s-5); padding:var(--s-8) var(--s-7); background:var(--bg); color:var(--tx); text-align:left}
	.gate-brand{margin:0 0 var(--s-3); font-family:var(--display); font-size:var(--fs-h); font-weight:700; letter-spacing:var(--ls-tight); color:var(--tx)}
	.gate-msg{margin:0; font-size:var(--fs-base); line-height:1.6; max-width:34em}
	.gate-msg b{color:var(--am); font-weight:400}
	.gate-note{margin:var(--s-3) 0 0; font-size:var(--fs-sm); color:var(--mut); max-width:34em}
	.app{overflow:hidden; height:100vh} /* no scrolling under the gate */
	.bar{flex-wrap:wrap; height:auto; padding:var(--s-4) var(--s-6); position:static}
	.work{display:block}
	.stage-col, .stage-fit{overflow:visible}
	.stage-col{padding:var(--s-6)}
	.inspector{border-left:none; border-top:var(--bw) solid var(--line)}
	.sec > summary{padding:var(--s-5) var(--s-6)}
	.sec-body{padding:0 var(--s-6) var(--s-6)}
}

@media (prefers-reduced-motion: reduce){
	*{transition:none !important; animation:none !important}
}
