/* The colours all come from the accent, the same way make_theme() derives them
   in the desktop build. js/theme.js writes these custom properties whenever the
   accent changes, so nothing here names a colour that cannot follow it. */
:root {
	--accent: #008080;
	/* The gauge handle. Shared, because the row of marks under the track is
	   inset by half of it to line up with where the handle can stop. */
	--thumb: 20px;
	--accent-light: #2e9999;
	--accent-dark: #006060;
	--on-accent: #f4f8f0;
	--on-accent-quiet: #9ac6c0;
	--accent-ink: #003434;
	--ink: #16211b;
	--muted: #6b7a70;
	--paper: #fcfdf9;
	--panel: #fafbf6;
	--page-bg: #f7f8f2;
	--button-bg: #f1f4ed;
	--button-border: #d9e1d5;
	--button-hover: #e4eedb;
	--button-hover-border: #b6c8a8;
	--button-press: #d1e5c2;
	--button-press-border: #89a779;
	--tab-closed: #eceee7;
	--tab-border: #c3d0bd;
	--warn: #a56931;
	--error: #ab4d37;
	--start: #18775c;
	--end: #a5633f;
	--radius: 8px;
	--header-height: 78px;
	--sidebar-width: 338px;
}

* { box-sizing: border-box; }

/* The hidden attribute is how this app shows and hides nearly everything, and
   a display: of any kind elsewhere would quietly beat it. */
[hidden] { display: none !important; }

html, body {
	height: 100%;
	margin: 0;
	font-family: "Yu Gothic UI", "Meiryo", "Noto Sans JP", "Hiragino Kaku Gothic ProN", system-ui, sans-serif;
	font-size: 14px;
	color: var(--ink);
	background: var(--page-bg);
	overflow: hidden;
}

/* --- header --------------------------------------------------------------- */

.header {
	height: var(--header-height);
	background: var(--accent);
	color: var(--on-accent);
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 0 16px 0 10px;
	position: relative;
}

/* The name is artwork now, not type. It is given a height and left to work
   out its own width, and allowed to shrink on a narrow header rather than
   push the rest of the row off the end.

   40px in a 78px band. What limits this is the band, not the picture:
   wordmark.png is 655x128, so even here it is drawn at a third of its own
   height and has room to spare on a 2x screen. Going much past 48px leaves
   too little air above and below, and the tallest thing already in the row
   is the 46px profile button. */
.header .wordmark { height: 40px; width: auto; max-width: 100%; min-width: 0; flex: 0 1 auto; object-fit: contain; }
/* Beside the name, small and quiet: it says which build this is, it is not
   something to read at a glance. */
.header .version { font-size: 11px; color: var(--on-accent-quiet); margin-left: 8px; align-self: center; }
.header .spacer { flex: 1; }
.header .banner { font-size: 12px; color: var(--on-accent-quiet); letter-spacing: 0.08em; }

.chrome-button {
	width: 34px;
	height: 34px;
	border: 0;
	border-radius: var(--radius);
	background: var(--accent-light);
	color: var(--on-accent);
	font-size: 15px;
	cursor: pointer;
}
.chrome-button:hover { filter: brightness(1.12); }

/* Their picture if there is one, their name if there is not, and either way the
   way in to the profile. The picture is cut to a circle when it is saved, so
   every place it is drawn is round without masking it again here. */
.portrait-button {
	min-width: 46px;
	height: 46px;
	padding: 0 12px;
	border: 0;
	border-radius: 23px;
	background: var(--accent-light);
	color: var(--on-accent);
	font-size: 14px;
	cursor: pointer;
	background-size: cover;
	background-position: center;
}
.portrait-button.has-picture { padding: 0; width: 46px; }

/* The engine's tooltip is a window outside the theme's reach, so the desktop
   build draws the name itself. Here the same choice keeps it under the picture
   rather than beside the pointer. */
.nickname-tip {
	position: absolute;
	top: calc(var(--header-height) - 6px);
	background: var(--accent-dark);
	color: var(--on-accent);
	border: 1px solid var(--accent-light);
	border-radius: 6px;
	padding: 4px 10px;
	font-size: 13px;
	white-space: nowrap;
	pointer-events: none;
	z-index: 900;
}

/* --- layout --------------------------------------------------------------- */

.body {
	display: flex;
	height: calc(100% - var(--header-height));
	min-height: 0;
}

.sidebar {
	width: var(--sidebar-width);
	min-width: 300px;
	flex: 0 0 auto;
	background: var(--panel);
	display: flex;
	flex-direction: column;
	min-height: 0;
}
.sidebar[hidden] { display: none; }

.divider {
	width: 6px;
	flex: 0 0 auto;
	cursor: col-resize;
	background: linear-gradient(to right, transparent 2px, var(--button-border) 2px, var(--button-border) 4px, transparent 4px);
}
.divider[hidden] { display: none; }

.map-area { position: relative; flex: 1 1 auto; min-width: 360px; }
#map { position: absolute; inset: 0; background: #e5ebe2; }
#map.picking { cursor: crosshair; }

/* The scale bar, dressed like the one the desktop build draws: a white strip
   at the bottom left with a dark rule under the reading. */
.leaflet-control-scale { margin: 0 0 14px 14px; }
.leaflet-control-scale-line {
	/* The width set on this is the length the bar stands for, so the padding
	   and the rules have to sit inside it rather than add to it. */
	box-sizing: border-box;
	background: rgba(255, 255, 255, 0.9);
	border: 0;
	border-bottom: 2px solid #294638;
	border-left: 2px solid #294638;
	border-right: 2px solid #294638;
	border-radius: 0;
	padding: 1px 6px 2px 6px;
	color: #294638;
	font-size: 12px;
	line-height: 14px;
	text-shadow: none;
}

/* --- tabs ----------------------------------------------------------------- */

/* Touching, so that the line each closed tab draws under itself runs on into
   the next and stops only at the open one. */
/* Above the tabs rather than inside the first page: it is the thing to press
   whichever page is open, and from the saved-places page it used to be out of
   reach entirely. */
.search-bar {
	display: flex;
	/* The gap under it is the point of the number: a finger aiming at the tabs
	   was landing on this instead, 12px away. */
	padding: 14px 14px 18px 14px;
	flex: 0 0 auto;
}
.search-bar .button { flex: 1 1 auto; }

.tab-row {
	display: flex;
	gap: 0;
	padding: 10px 14px 0 14px;
}

.tab {
	flex: 1 1 0;
	font: inherit;
	font-size: 13px;
	padding: 7px 8px;
	cursor: pointer;
	background: var(--tab-closed);
	color: var(--ink);
	border: 1px solid var(--tab-border);
	border-bottom-width: 1px;
	border-top-width: 1px;
	border-radius: 9px 9px 0 0;
	margin-top: 3px;
	user-select: none;
}
/* The one in front stands a little taller than the ones behind it, is open at
   the bottom where it meets the page, and is rounded at the top only. */
.tab.open {
	background: var(--paper);
	border-top-width: 3px;
	border-bottom-width: 0;
	margin-top: 0;
	padding-bottom: 8px;
}
.tab.dragging { opacity: 0.5; }
.tab.drop-target { background: var(--button-hover); }

.pages { flex: 1 1 auto; min-height: 0; display: flex; }
.page { flex: 1 1 auto; overflow-y: auto; overflow-x: hidden; background: var(--paper); }
.page[hidden] { display: none; }
.gutter { padding: 14px 14px 28px 14px; display: flex; flex-direction: column; gap: 8px; }

/* --- the lock ------------------------------------------------------------- */

/* Over everything, opaque, and up before the app is built: what is behind it
   is an empty shell, since nothing is read until there is a key to read it
   with. */
.gate {
	position: fixed;
	inset: 0;
	z-index: 200;
	background: var(--page-bg);
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 16px;
	overflow: auto;
}

.gate-card {
	width: 100%;
	max-width: 420px;
	background: var(--panel);
	border: 1px solid var(--button-border);
	border-radius: 14px;
	padding: 26px 24px 22px 24px;
	display: flex;
	flex-direction: column;
	gap: 6px;
	box-shadow: 0 18px 50px rgba(22, 33, 27, 0.14);
}

/* While the lock is up the app's own chrome is not just covered but gone:
   the chips over the map carry z-indexes of their own, and an empty shell
   showing around the card looks like a page that half failed to load. */
body.locked > .header, body.locked > .body, body.locked > .window-layer { display: none; }

/* The card is a column, and a row wrapped in a div has to be one too, or the
   label and the field sit side by side while every other pair is stacked. */
#gate-again-row, #gate-invite-row { display: flex; flex-direction: column; gap: 6px; }
.gate-mark { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
.gate-mark img { width: 34px; height: 34px; }
.gate-mark span { font-size: 19px; letter-spacing: 0.01em; }
.gate-title { font-size: 17px; font-weight: 600; margin: 4px 0 0 0; }
.gate-lead { font-size: 13px; color: var(--muted); line-height: 1.7; margin: 0 0 8px 0; }
.gate-label { font-size: 13px; margin-top: 6px; }
/* Beside the label rather than under the field: it says who the field is for,
   which is worth knowing before it is typed in rather than after. */
.gate-optional { font-size: 11px; color: var(--muted); margin-left: 8px; font-weight: normal; }
/* Under both fields, because it governs both. Small and quiet: it is a
   convenience while typing, not a thing to decide about. The 16px box is the
   smallest that is comfortable to hit with a thumb. */
.gate-reveal { display: flex; align-items: center; gap: 7px; margin-top: 10px; }
.gate-reveal input { width: 16px; height: 16px; margin: 0; accent-color: var(--accent); }
.gate-reveal label { font-size: 12px; color: var(--muted); cursor: pointer; }
.gate-reveal label:hover { color: var(--ink); }
.gate-card #gate-invite { text-transform: uppercase; letter-spacing: 0.06em; }
.gate .gate-go { margin-top: 14px; height: 44px; font-size: 15px; }
.gate-note { font-size: 11px; color: var(--muted); line-height: 1.7; margin: 12px 0 0 0; }
.gate-error {
	font-size: 13px;
	color: var(--error);
	line-height: 1.6;
	margin: 10px 0 0 0;
}
.gate-link {
	align-self: flex-start;
	margin-top: 10px;
	padding: 0;
	border: 0;
	background: none;
	color: var(--muted);
	font-size: 11px;
	text-decoration: underline;
	cursor: pointer;
}
.gate-link:hover { color: var(--ink); }
/* Not every word in that place is a refusal. A note about what the screen just
   did, or a message that something worked, in the colour of a wrong password
   reads as one. */
.gate-error.soft { color: var(--muted); }

/* The one note in the app that is asking for something rather than reporting
   something. Tinted, not red: nothing has gone wrong yet, and that is the
   whole point of saying it now. */
.nudge {
	margin: 8px 10px 0 10px;
	padding: 9px 11px;
	border: 1px solid var(--accent);
	border-radius: 8px;
	background: color-mix(in srgb, var(--accent) 12%, var(--paper));
}
.nudge-words {
	margin: 0 0 7px 0;
	font-size: 12px;
	line-height: 1.6;
	color: var(--ink);
}
.nudge-row { display: flex; gap: 6px; }
.nudge-row .button { flex: 1 1 auto; }
/* The one link somebody may be looking for before they have an account,
   so it is not the same grey whisper as "forgot my password". */
.gate-switch {
	margin-top: 12px;
	color: var(--accent-ink);
	font-size: 12px;
}
.gate-switch:hover { color: var(--accent-ink); text-decoration-thickness: 2px; }

/* --- controls ------------------------------------------------------------- */

h2 { font-size: 17px; font-weight: 600; margin: 6px 0 2px 0; }
hr { border: 0; border-top: 1px solid var(--button-border); width: 100%; margin: 10px 0; }

.field-title { font-size: 14px; margin-top: 4px; }
.field-title.start { color: var(--start); }
.field-title.end { color: var(--end); }

.row { display: flex; gap: 8px; align-items: stretch; }
.row .grow { flex: 1 1 auto; }
.presets .button { font-size: 12px; }
/* Nine levels read better as three rows of three than as one long row, which
   is the shape the desktop settings use. */
.zoom-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.zoom-grid .button { font-size: 12px; }

input[type="text"], input[type="number"], input[type="date"], input[type="email"], input[type="password"], select {
	flex: 1 1 auto;
	min-width: 0;
	height: 39px;
	padding: 0 10px;
	font: inherit;
	color: var(--ink);
	background: #fff;
	border: 1px solid #ccd8cb;
	border-radius: var(--radius);
}
input[type="text"]:focus, input[type="number"]:focus, input[type="date"]:focus, select:focus {
	outline: none;
	border: 2px solid var(--accent);
	padding: 0 9px;
}

.button {
	font: inherit;
	font-size: 14px;
	min-height: 38px;
	padding: 8px 12px;
	cursor: pointer;
	color: var(--ink);
	background: var(--button-bg);
	border: 1px solid var(--button-border);
	border-radius: var(--radius);
	text-align: center;
}
.button:hover { background: var(--button-hover); border-color: var(--button-hover-border); }
.button:active { background: var(--button-press); border-color: var(--button-press-border); }
.button:disabled { background: #e8ebe5; border-color: transparent; color: var(--muted); cursor: default; }
.button.small { min-height: 29px; padding: 4px 10px; font-size: 13px; }
.button.mark { flex: 0 0 auto; min-width: 44px; }
.button[hidden] { display: none; }

/* The one slab of the accent: the search button, which is the thing to press
   first. */
.button.primary {
	min-height: 48px;
	font-size: 15px;
	background: var(--accent);
	border-color: var(--accent);
	color: var(--on-accent);
	border-radius: 9px;
}
.button.primary:hover { background: var(--accent-light); border-color: var(--accent-light); }
.button.primary:active { background: var(--accent-dark); border-color: var(--accent-dark); }

/* What there is to do with a route once it is drawn. These were the same pale
   grey as every other row and went unnoticed, so they carry the accent: a wash
   of it behind, a line of it around, and its readable form as the text. */
.button.action {
	background: color-mix(in srgb, var(--accent) 12%, var(--paper));
	border: 2px solid color-mix(in srgb, var(--accent) 55%, var(--paper));
	color: var(--accent-ink);
	border-radius: 9px;
}
.button.action:hover { background: color-mix(in srgb, var(--accent) 24%, var(--paper)); }
.button.action:active { background: color-mix(in srgb, var(--accent) 38%, var(--paper)); border-color: var(--accent-ink); }

.slider-row { display: flex; justify-content: space-between; font-size: 13px; margin-top: 6px; }

/* The five positions have to be visible and tappable, which means the marks
   under the track have to line up with where the handle can actually stop. The
   handle stops half a handle's width in from each end, so the row of marks is
   inset by exactly that - which means the handle's width has to be ours rather
   than the browser's, and that is why the gauge is drawn here from scratch
   instead of being left to accent-color.

   --at (0..1) is written by js/main.js whenever the value changes:
   appearance:none takes the filled part of the track away with everything
   else, and the fill is what says at a glance which side of the middle the
   gauge is on. It is worked out the same way the marks are, so the fill ends
   under the handle rather than a few pixels off it. */
input[type="range"] {
	--at: 0.5;
	width: 100%;
	height: 24px;
	appearance: none;
	-webkit-appearance: none;
	background: transparent;
	margin: 0;
	cursor: pointer;
}
input[type="range"]::-webkit-slider-runnable-track {
	height: 6px;
	border-radius: 3px;
	background: linear-gradient(to right, var(--accent)
		calc(var(--thumb) / 2 + (100% - var(--thumb)) * var(--at)), var(--button-border) 0);
}
input[type="range"]::-moz-range-track {
	height: 6px;
	border-radius: 3px;
	background: linear-gradient(to right, var(--accent)
		calc(var(--thumb) / 2 + (100% - var(--thumb)) * var(--at)), var(--button-border) 0);
}
input[type="range"]::-webkit-slider-thumb {
	-webkit-appearance: none;
	width: var(--thumb);
	height: var(--thumb);
	border-radius: 50%;
	background: var(--accent);
	border: 2px solid var(--paper);
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
	/* (track height - thumb height) / 2, which is what centres it on the line. */
	margin-top: calc((6px - var(--thumb)) / 2);
}
input[type="range"]::-moz-range-thumb {
	width: var(--thumb);
	height: var(--thumb);
	border-radius: 50%;
	background: var(--accent);
	border: 2px solid var(--paper);
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
input[type="range"]:disabled { cursor: default; opacity: 0.5; }

/* The marks. Inset by half a handle so that mark i sits exactly where the
   handle stops at position i, and each one is a button so that a finger has
   something to aim at rather than a 2px line. */
.ticks {
	position: relative;
	height: 22px;
	margin: -2px calc(var(--thumb) / 2) 2px calc(var(--thumb) / 2);
}
.tick {
	position: absolute;
	top: 0;
	transform: translateX(-50%);
	width: 36px;
	height: 22px;
	padding: 0;
	border: 0;
	background: transparent;
	cursor: pointer;
	display: flex;
	justify-content: center;
	align-items: flex-start;
}
.tick::before {
	content: "";
	width: 2px;
	height: 7px;
	border-radius: 1px;
	background: var(--button-border);
}
/* The one the gauge is on, so the marks say where it is as well as where it
   could go. */
.tick[aria-current="true"]::before { background: var(--accent); height: 10px; width: 3px; }
.tick:disabled { cursor: default; }

.check { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border: 1px solid var(--button-border); border-radius: var(--radius); background: var(--button-bg); cursor: pointer; }
.check:has(input:checked) { background: var(--button-press); border-color: var(--button-press-border); }
.check input { accent-color: var(--accent); width: 16px; height: 16px; }

.note { font-size: 11px; color: var(--muted); margin: 2px 0; line-height: 1.6; }
.detail { font-size: 11px; color: var(--muted); margin: 0; }
.status { font-size: 13px; color: var(--muted); margin: 2px 0; min-height: 1em; }
.status.error { color: var(--error); }
.route-hint { font-size: 12px; color: var(--warn); margin: 2px 0; }
.summary { font-size: 23px; margin: 6px 0 0 0; }

.list { display: flex; flex-direction: column; gap: 6px; }
.list .entry { display: flex; gap: 6px; }
.list .entry .name {
	flex: 1 1 auto;
	min-width: 0;
	text-align: left;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	font-size: 12px;
}

.leg { margin-top: 10px; }
.leg h3 { font-size: 13px; margin: 0 0 4px 0; color: var(--accent-ink); }
.leg ol { margin: 0; padding-left: 1.3em; font-size: 12px; color: var(--muted); line-height: 1.7; }

/* --- the map's own furniture --------------------------------------------- */

/* Two stacked rows and, under them, the panel - so that the panel clears
   whatever the rows take rather than a fixed offset the second row broke. */
.map-top {
	position: absolute;
	top: 14px;
	left: 14px;
	right: 70px;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 8px;
	z-index: 500;
	/* It spans the width now, so its empty part must not swallow a drag of the
	   map underneath. The rows take their own clicks back. */
	pointer-events: none;
}
.map-row { display: flex; gap: 8px; flex-wrap: wrap; pointer-events: auto; }
.map-side { position: absolute; top: 14px; right: 14px; display: flex; flex-direction: column; gap: 8px; z-index: 500; }
.button.chip { background: var(--paper); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12); }
/* Said again here because the line above cancels it. `.button:hover` and
   `.button.chip` have the same specificity, and the chip rule is written
   later, so it painted over the hover and these two gave no feedback at
   all. A tint of the accent rather than the sidebar's pale green: over
   map tiles the grey-green reads as part of the map. */
.button.chip:hover {
	background: color-mix(in srgb, var(--accent) 22%, var(--paper));
	border-color: var(--accent);
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.22);
}
.button.chip:active {
	background: color-mix(in srgb, var(--accent) 44%, var(--paper));
	border-color: var(--accent-dark);
	box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
}
.button.chip.square { width: 44px; min-width: 44px; padding: 0; font-size: 18px; }
/* On the map these carry a chip's shadow and an action's colour. .chip is
   written after .action and would otherwise paint over it. */
.button.chip.action {
	background: color-mix(in srgb, var(--accent) 14%, var(--paper));
	border: 2px solid color-mix(in srgb, var(--accent) 55%, var(--paper));
	color: var(--accent-ink);
}
.button.chip.action:hover { background: color-mix(in srgb, var(--accent) 26%, var(--paper)); }
.button.chip.action:active { background: color-mix(in srgb, var(--accent) 38%, var(--paper)); border-color: var(--accent-ink); }
/* Still a button to look at, just not one to press yet: over map tiles the
   plain grey of .button:disabled reads as part of the map. */
.button.chip.action:disabled {
	background: var(--paper);
	border-color: var(--button-border);
	color: var(--muted);
}

/* Nothing is written over the map unless there is something to say. */
.map-panel {
	background: var(--paper);
	border-radius: var(--radius);
	padding: 8px 12px;
	font-size: 13px;
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
	white-space: pre-line;
	/* Something to read, not something to press. */
	pointer-events: none;
}
/* The one in the corner is laid out by the column it is in; the other is on
   its own at the bottom, clear of the scale bar. */
.map-top .map-panel { align-self: stretch; }
.map-panel.bottom { position: absolute; left: 14px; right: 70px; bottom: 56px; z-index: 500; }
.map-panel[hidden] { display: none; }

.rc-marker-wrap { background: none; border: 0; }
.rc-marker {
	width: 34px;
	height: 34px;
	border-radius: 17px;
	border: 3px solid #fff;
	color: #fff;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 15px;
	font-weight: 600;
	box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
}
/* The ring that spreads where the map was told to look.

   It grows by transform, not by r: Leaflet draws a circleMarker as a <path>
   with the circle written into its d, and r is a geometry property of
   <circle>, so animating it did nothing at all here - the ring sat at its
   one radius and only blinked. transform-box pins the growth to the ring's
   own centre, wherever on the map that is, and the stroke is kept at the
   width it is given rather than being scaled up with everything else. */
.rc-highlight {
	transform-box: fill-box;
	transform-origin: center;
	vector-effect: non-scaling-stroke;
	animation: rc-ring 1.67s linear infinite;
}
/* The second pair of rings, half a cycle behind the first: a negative delay
   starts them already half way out rather than waiting. */
.rc-highlight-late { animation-delay: -0.835s; }
@keyframes rc-ring {
	/* 5.29 is 74 / 14 - the radius mapview.js draws it at, and the one the
	   desktop build opens the ring out to. */
	from { transform: scale(1); opacity: 1; }
	to { transform: scale(5.29); opacity: 0; }
}

/* --- menus ---------------------------------------------------------------- */

.menu {
	position: fixed;
	z-index: 1200;
	min-width: 190px;
	padding: 4px 0;
	background: var(--paper);
	border: 1px solid var(--tab-border);
	border-radius: var(--radius);
	box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
}
.menu[hidden] { display: none; }
.menu button {
	display: block;
	width: 100%;
	text-align: left;
	font: inherit;
	font-size: 13px;
	padding: 7px 14px;
	border: 0;
	background: none;
	color: var(--ink);
	cursor: pointer;
}
.menu button:hover:not(:disabled) { background: var(--button-hover); }
.menu button:disabled { color: var(--muted); cursor: default; }
.menu hr { margin: 4px 0; }

/* --- windows and dialogs -------------------------------------------------- */

.window-layer { position: fixed; inset: 0; z-index: 1000; }
.window-layer[hidden] { display: none; }
/* The layer only catches the pointer where a window actually is, so the map
   underneath stays usable - the desktop build's windows behave the same way. */
.window-layer > * { pointer-events: auto; }
.window-layer { pointer-events: none; }

.window {
	position: absolute;
	display: flex;
	flex-direction: column;
	background: var(--paper);
	border: 2px solid var(--accent-dark);
	border-radius: 10px;
	box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
	overflow: hidden;
	max-height: calc(100vh - 32px);
}
.window-bar {
	display: flex;
	align-items: center;
	height: 34px;
	padding-left: 12px;
	background: var(--accent);
	color: var(--on-accent);
	font-size: 14px;
	cursor: move;
	user-select: none;
}
.window-title { flex: 1 1 auto; }
.window-close {
	width: 34px;
	height: 28px;
	margin-right: 3px;
	border: 0;
	border-radius: 6px;
	background: var(--accent);
	color: var(--on-accent);
	font-size: 16px;
	cursor: pointer;
}
.window-close:hover { background: var(--accent-light); }
.window-body { padding: 14px 18px 18px 18px; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; }

.modal-backdrop {
	position: absolute;
	inset: 0;
	background: rgba(22, 33, 27, 0.25);
	pointer-events: auto;
}

.dialog-text { white-space: pre-line; font-size: 13px; line-height: 1.8; margin: 0; }
.dialog-buttons { display: flex; gap: 10px; justify-content: center; margin-top: 10px; }

.swatches { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.swatch { height: 34px; border-radius: 6px; border: 2px solid transparent; cursor: pointer; }
.swatch.chosen { border-color: var(--accent-ink); }

.portrait-stage {
	position: relative;
	width: 240px;
	height: 240px;
	margin: 0 auto;
	overflow: hidden;
	border-radius: 50%;
	background: var(--button-bg);
	cursor: grab;
	touch-action: none;
}
.portrait-stage.dragging { cursor: grabbing; }
.portrait-stage canvas { position: absolute; inset: 0; }

.profile-picture {
	width: 96px;
	height: 96px;
	border-radius: 48px;
	background: var(--button-bg);
	background-size: cover;
	background-position: center;
	flex: 0 0 auto;
}
.profile-row { display: flex; gap: 14px; align-items: center; }
.profile-row .stack { display: flex; flex-direction: column; gap: 8px; flex: 1 1 auto; }

.candidate {
	display: block;
	width: 100%;
	text-align: left;
	font-size: 13px;
	line-height: 1.5;
}
.candidate b { font-weight: 600; font-size: 14px; }
.candidate span { color: var(--muted); font-size: 12px; }

/* --- a phone -------------------------------------------------------------- */

/* The panel cannot sit beside the map on a phone: it is 338px wide and asks for
   300 at the least, which on a 390px screen leaves the map nothing. So it
   becomes a sheet over the map instead, and the map has the screen. The toggle
   in the header still opens and closes it, which reads the same way for a
   sheet as for a panel.

   720px rather than a phone's width: a narrow window on a desktop has the same
   problem, and this is the width below which the two no longer fit. */
@media (max-width: 720px) {
	:root { --header-height: 60px; }

	.header { padding: 0 10px 0 6px; gap: 6px; }
	/* The band is 60px here rather than 78, so the name comes down with it
	   and keeps roughly the same share of it. */
	.header .wordmark { height: 30px; }
	/* Which build it is matters less than the room it takes here. */
	.header .version { display: none; }
	.header .banner { display: none; }

	.body { display: block; position: relative; }
	.map-area { position: absolute; inset: 0; min-width: 0; }
	/* Nothing to drag: the sheet is as wide as the screen. */
	.divider { display: none !important; }

	.sidebar {
		position: absolute;
		left: 0;
		right: 0;
		bottom: 0;
		width: auto;
		min-width: 0;
		max-height: 68%;
		z-index: 500;
		border-radius: 16px 16px 0 0;
		box-shadow: 0 -6px 24px rgba(0, 0, 0, 0.18);
	}
	/* A bar to say the sheet can be put away, in the place a thumb reaches. */
	.tab-row { padding: 14px 10px 0 10px; }
	.sidebar::before {
		content: "";
		position: absolute;
		top: 6px;
		left: 50%;
		width: 44px;
		height: 4px;
		margin-left: -22px;
		border-radius: 2px;
		background: var(--tab-border);
	}

	.gutter { padding: 12px 12px 24px 12px; }

	/* A finger is not a mouse pointer: 44px is the size it can be sure of. */
	.button { min-height: 44px; }
	.button.small { min-height: 40px; }
	.check { min-height: 44px; display: flex; align-items: center; }
	input[type="text"], input[type="number"], input[type="date"], input[type="email"], input[type="password"], select { height: 44px; }
	input[type="range"] { height: 32px; }
	.chrome-button { width: 40px; height: 40px; }

	/* The windows are placed in pixels by the code that opens them, so they are
	   held inside the screen here rather than there. */
	.window { max-width: calc(100vw - 16px); max-height: calc(100vh - 80px); }
	.menu { max-width: calc(100vw - 16px); }
}
