/* ============================================================
   MY BOXES - STRUCTURE

   No colours in this file. Every colour lives in
   myBoxes-Colors-Maroon.css and arrives here through a var(), the same
   split as main.css / siteTheme-Colors-Blue.css.

   If you find yourself typing a # in this file, it belongs in the
   colour file instead - that is the whole point of the split.
   ============================================================ */

:root {
	--box-mono: ui-monospace, "Cascadia Code", Consolas, "Liberation Mono", monospace;
	--box-display: 'Trebuchet MS', 'Segoe UI', Arial, sans-serif;
}

/* Core caps .Master at 1920px and centres it, which turns into a page
   sitting in the middle of dead space the moment the viewport is wider
   - zoom out and it is unmistakable. Six other pages already override
   this, so it is the house pattern rather than a workaround.

   main.css zeroes the body margin for everybody now, so the override
   this file used to carry is gone.

   The flex column is what lets the workspace take the leftover height
   instead of a guessed vh number: header, nav, toolbar and footer take
   what they need, and .box-app absorbs the rest. No magic constant to
   fall out of step when the toolbar wraps to two lines. */
.Master {
	max-width: none;
	min-height: 100vh;
	min-height: 100dvh;
	display: flex;
	flex-direction: column;
}

.box-app {
	color: var(--box-ink);
	flex: 1 1 auto;
	display: flex;
	flex-direction: column;

	/* Without this a flex child refuses to shrink below its content,
	   and the columns would push the page taller instead of scrolling
	   inside themselves. */
	min-height: 0;
}

/* The app ships hidden until the account is confirmed - see the note in
   myBoxes.html - and the display: flex above beats the hidden attribute
   on its own, so the empty app showed through while that was checked. */
.box-app[hidden] {
	display: none !important;
}

/* ---------------- toolbar ---------------- */

/* The toolbar and the crumbs stay at the top of the window once the site
   header has scrolled away. js/myBoxes.js keeps --box-bars-h at their
   height, so the floating panes below can sit underneath them. The
   background is opaque or the list would show through. */
.box-bars {
	position: sticky;
	top: 0;
	z-index: 5;
	background: var(--box-ground);
}

.box-toolbar {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 6px;
	padding: 8px 4px;
	border-bottom: 1px solid var(--box-rule);
}

.box-toolbar-gap {
	flex: 1 1 auto;
}

/* The gear's menu. A popover, so the browser's own stylesheet centres
   it in the window; inset and margin undo that, and js/myBoxes.js sets
   top and --box-menu-right to hang it under the gear, right edges lined
   up. Clamped so a gear on a wrapped phone bar cannot push it off
   either side. */
.box-menu {
	--box-menu-width: min(17rem, calc(100vw - 16px));
	inset: auto;
	margin: 0;
	width: var(--box-menu-width);
	left: clamp(8px,
		calc(var(--box-menu-right, 100vw) - var(--box-menu-width)),
		calc(100vw - 8px - var(--box-menu-width)));
	padding: 6px;
	border: 1px solid var(--box-rule-strong);
	border-radius: 6px;
	background: var(--box-raised);
	color: var(--box-ink);
	box-shadow: 0 6px 20px var(--shadow);
}

/* Buttons and a link, all looking like one list. */
.box-menu-item {
	display: block;
	width: 100%;
	text-align: left;
	font-family: inherit;
	font-size: calc(13px * var(--font-scale, 1));
	padding: 7px 10px;
	border: 0;
	border-radius: 4px;
	background: none;
	color: var(--box-ink);
	text-decoration: none;
	cursor: pointer;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.box-menu-item:hover,
.box-menu-item:focus-visible {
	background: var(--box-accent);
	color: var(--box-on-accent);
	outline: none;
}

.box-menu-item[hidden] {
	display: none;
}

.box-menu-rule {
	border: 0;
	border-top: 1px solid var(--box-rule);
	margin: 5px 4px;
}

/* The adding buttons and the Edit buttons take turns on the bar. The
   group is only a switch, never a box of its own, so its buttons sit in
   the bar's flex row and keep its gap and its wrapping. contents beats
   the browser's own [hidden] rule, so hidden has to be said again. */
.box-tool-group {
	display: contents;
}

.box-tool-group[hidden] {
	display: none;
}

.box-btn {
	font-family: inherit;
	font-size: calc(13px * var(--font-scale, 1));
	line-height: 1.4;
	padding: 5px 12px;
	border: 1px solid var(--box-rule-strong);
	border-radius: 4px;
	background: var(--box-raised);
	color: var(--box-ink-muted);
	cursor: pointer;
	white-space: nowrap;
	text-decoration: none;
	display: inline-block;
}

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

.box-btn:focus-visible {
	outline: 2px solid var(--box-accent);
	outline-offset: 1px;
}

/* Fixed width, because the A inside changes size and the toolbar
   should not shuffle every time you press it. */
.box-font-bt {
	width: 42px;
	padding: 5px 0;
	line-height: 1.4;
	text-align: center;
}

.box-font-a {
	font-family: var(--box-display);
	font-weight: 700;

	/* Deliberately NOT scaled by the page variable the way everything
	   else is - it is scaled by it. Small A at Smallest, big A at
	   Biggest, so the button says what the setting is. */
	font-size: calc(8px + 6px * var(--font-scale, 1));
}

/* Icon only, so it needs its own width rather than a label's. */
.box-theme-bt {
	padding: 5px 11px;
	line-height: 1.4;
}

/* A toggle that is on, eg Repeat in the player. */
.box-btn[aria-pressed="true"] {
	border-color: var(--box-accent);
	background: var(--box-accent-soft);
	color: var(--box-accent);
}

.box-btn-primary {
	background: var(--box-accent);
	border-color: var(--box-accent);
	color: var(--box-on-accent);
	font-weight: 600;
}

.box-btn-primary:hover {
	background: var(--box-accent-strong);
	border-color: var(--box-accent-strong);
	color: var(--box-on-accent);
}

.box-btn-danger:hover {
	border-color: var(--box-accent);
	background: var(--box-accent-soft);
	color: var(--box-accent);
}

/* The core stylesheet stretches every text input to 100%, which would
   make the search field eat the toolbar. */
.box-search {
	width: auto;
	flex: 0 1 240px;
	min-width: 140px;
	font-size: calc(13px * var(--font-scale, 1));
	padding: 5px 10px;
	border: 1px solid var(--box-rule-strong);
	border-radius: 4px;
}

/* ---------------- breadcrumb ---------------- */

.box-crumbs {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 4px;
	padding: 7px 4px;
	font-family: var(--box-mono);
	font-size: calc(12px * var(--font-scale, 1));
	border-bottom: 1px solid var(--box-rule);
}

.box-crumb {
	font-family: inherit;
	font-size: inherit;
	background: none;
	border: 0;
	padding: 2px 4px;
	border-radius: 3px;
	color: var(--box-ink-muted);
	cursor: pointer;
}

.box-crumb:hover {
	color: var(--box-accent);
	background: var(--box-accent-soft);
}

.box-crumb:last-child {
	color: var(--box-ink);
	font-weight: 600;
}

.box-crumb-sep {
	color: var(--box-ink-faint);
}

/* The offer to move a browser's worth of boxes up to the account.
   Sits between the breadcrumb and the workspace so it is unmissable
   without being a dialog that has to be dismissed before working. */
.box-handover {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px 12px;
	padding: 10px 12px;
	border-width: 1px;
	border-style: solid;
	border-radius: 4px;
	margin: 8px 4px;
}

.box-handover-text {
	flex: 1 1 260px;
	font-size: calc(13px * var(--font-scale, 1));
	line-height: 1.5;
}

/* ---------------- workspace ---------------- */

.box-workspace {
	display: grid;
	grid-template-columns:
		minmax(0, 1fr)
		7px
		clamp(240px, var(--box-pane-w, 34%), 68%);
	flex: 1 1 auto;
	min-height: 380px;
	border-bottom: 1px solid var(--box-rule);
}

/* The columns scroll sideways as you go deeper; the page never does. */
.box-strip {
	display: flex;
	align-items: stretch;
	overflow-x: auto;
	overflow-y: hidden;
}

/* A 7px grab area with a 1px line down the middle of it. Fitts's law:
   the thing you have to hit is wider than the thing you can see. */
.box-splitter {
	position: relative;
	cursor: col-resize;

	/* Without this a touch drag scrolls the page instead of moving
	   the handle. */
	touch-action: none;
}

.box-splitter::before {
	content: '';
	position: absolute;
	top: 0;
	bottom: 0;
	left: 3px;
	width: 1px;
}

.box-splitter:hover::before,
.box-splitter:focus-visible::before,
.box-splitter.is-dragging::before {
	left: 2px;
	width: 3px;
}

.box-splitter:focus-visible {
	outline: none;
}

.box-strip::-webkit-scrollbar {
	height: 14px;
}

.box-strip::-webkit-scrollbar-thumb {
	border-radius: 7px;
	border: 3px solid transparent;
	background-clip: content-box;
}

/* Each column is as wide as its longest title, up to a cap. The cap
   grows with bigger text but never shrinks with smaller - scaled both
   ways, smaller text shrank the cap with it and showed exactly the same
   words, only smaller. This way smaller text shows more of every title,
   and bigger text shows as much as it always did. */
.box-col {
	flex: 0 0 auto;
	width: max-content;
	min-width: calc(150px * var(--font-scale, 1));
	max-width: calc(320px * max(1, var(--font-scale, 1)));
	display: flex;
	flex-direction: column;
	overflow-y: auto;
	border-right: 1px solid var(--box-rule);
	padding-bottom: 8px;
}

/* The last column takes any room left before the detail pane, so a
   pane dragged far to the right leaves no dead gap and ⟷ sits at the
   edge. Free space only - it never makes the strip scroll - and only up
   to its cap. */
.box-col:last-child {
	flex-grow: 1;
	border-right: 0;
}

.box-col-head {
	position: sticky;
	top: 0;
	background: var(--box-surface);
	border-bottom: 1px solid var(--box-rule);
	font-family: var(--box-display);
	font-size: calc(10px * var(--font-scale, 1));
	font-weight: 700;
	letter-spacing: 1.6px;
	text-transform: uppercase;
	color: var(--box-ink-faint);
	padding: 7px 4px 7px 10px;
	display: flex;
	align-items: center;
	gap: 6px;
}

.box-col-title {
	flex: 1 1 auto;
	min-width: 0;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* Show all text, at the right of a column's heading. Quiet until it is
   wanted, lit while it is on. */
.box-col-wide {
	flex: none;
	font: inherit;
	letter-spacing: 0;
	line-height: 1;
	padding: 2px 6px;
	border: 1px solid transparent;
	border-radius: 3px;
	background: none;
	color: var(--box-ink-faint);
	cursor: pointer;
}

.box-col-wide:hover,
.box-col-wide:focus-visible {
	border-color: var(--box-rule-strong);
	color: var(--box-ink);
	outline: none;
}

.box-col-wide[aria-pressed="true"] {
	border-color: var(--box-accent);
	color: var(--box-accent);
}

/* The cap lifted, so every title fits. Still a cap, against the window,
   so one very long title cannot push every other column off screen. */
.box-col.is-wide {
	max-width: 70vw;
}

.box-col-empty {
	max-width: calc(190px * var(--font-scale, 1));
	padding: 12px 10px;
	font-size: calc(12px * var(--font-scale, 1));
	color: var(--box-ink-faint);
	line-height: 1.5;
}

.box-row {
	display: flex;
	align-items: center;
	gap: 7px;
	padding: 6px 10px;
	font-size: calc(13px * var(--font-scale, 1));
	color: var(--box-ink-muted);
	cursor: pointer;
	border-left: 3px solid transparent;
}

.box-row:hover {
	background: var(--box-surface);
}

.box-row.is-selected {
	background: var(--box-accent-soft);
	border-left-color: var(--box-accent);
	color: var(--box-ink);
	font-weight: 600;
}

/* ---- the row Cut or Copy is holding ----

   Its own mark, because you walk away from it to find where it goes.
   Copy is a solid edge - the original stays where it is. Cut is dashed
   and faded, the way a desktop shows a file that is about to move. The
   outline sits inside the row so it never shifts the column. */
.box-row.is-held {
	background: var(--box-held-soft);
	border-left-color: var(--box-held);
	outline: 1px solid var(--box-held);
	outline-offset: -1px;
}

.box-row.is-held-cut {
	outline-style: dashed;
	opacity: 0.7;
}

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

.box-chevron {
	color: var(--box-ink-faint);
	font-size: calc(13px * var(--font-scale, 1));
	flex: none;
}

/* ---- dragging a row to re-parent it ---- */

/* The row being carried stays visible but recedes, so you can still see
   what you picked up while judging where to put it. */
.box-row.is-dragging {
	opacity: 0.4;
}

/* Drawn inside the element rather than around it, so the highlight cannot
   nudge anything and make the target move while you are aiming at it. */
.box-row.is-drop-target,
.box-col.is-drop-target {
	outline-width: 2px;
	outline-style: solid;
	outline-offset: -2px;
}

/* Landing in the gap rather than in a box. A line, not a highlight,
   because a gap is what is being aimed at - the rows either side are both
   staying exactly where they are.

   Inset shadow for the same reason the outline above is inset: a border
   or an added element would make the row 2px taller and shuffle the
   column downwards under the cursor that is aiming at it. */
.box-row.is-drop-above {
	box-shadow: inset 0 2px 0 var(--box-accent);
}

.box-row.is-drop-below {
	box-shadow: inset 0 -2px 0 var(--box-accent);
}

/* Kind chips. Each kind gets its own colour so a column of mixed
   things reads at a glance without having to be read. */
.box-kind {
	font-family: var(--box-mono);
	font-size: calc(9px * var(--font-scale, 1));
	font-weight: 700;
	letter-spacing: 0.5px;
	padding: 1px 5px;
	border: 1px solid currentColor;
	border-radius: 3px;
	flex: none;
	line-height: 1.5;
}

.box-kind-box  { color: var(--box-accent); }
.box-kind-link { color: var(--box-ok); }
.box-kind-note { color: var(--box-warn); }
.box-kind-code { color: var(--box-ink-faint); }

/* ---- the row the speakers are on ---- */

/* Not the same thing as .is-selected, and often not even in the same
   column. Selection is where you are; this is what you can hear. */
.box-row.is-playing {
	background: var(--box-playing-soft);
	border-left-color: var(--box-ok);
	color: var(--box-ink);
	font-weight: 600;
}

/* Both at once is the ordinary case - you started it and you are still
   standing there. Selection keeps the background, because that is still
   where you are; the green edge and the bars say what is playing. */
.box-row.is-selected.is-playing {
	background: var(--box-accent-soft);
	border-left-color: var(--box-ok);
}

/* Three bars on a keyframe rather than an animated GIF: it takes its
   colour from the theme, costs no request, and can be told to stop. */
.box-playing-mark {
	display: inline-flex;
	align-items: flex-end;
	gap: 2px;
	height: calc(10px * var(--font-scale, 1));
	flex: none;
}

.box-playing-mark i {
	display: block;
	width: 2px;
	height: 100%;
	background: var(--box-ok);
	transform-origin: 50% 100%;
	animation: box-eq 900ms ease-in-out infinite;
}

.box-playing-mark i:nth-child(2) { animation-delay: -300ms; }
.box-playing-mark i:nth-child(3) { animation-delay: -600ms; }

@keyframes box-eq {
	0%, 100% { transform: scaleY(0.3); }
	50%      { transform: scaleY(1); }
}

/* Somebody who asked for less motion still has to be able to find the
   playing row, so the bars stay and only the movement goes. */
@media (prefers-reduced-motion: reduce) {
	.box-playing-mark i {
		animation: none;
		transform: scaleY(0.65);
	}
}

/* ---------------- detail pane ---------------- */

.box-detail-pane {
	overflow-y: auto;
	background: var(--box-surface);
	padding: 14px 16px;
}

.box-detail-empty {
	color: var(--box-ink-faint);
	font-size: calc(13px * var(--font-scale, 1));
	line-height: 1.6;
	padding-top: 20px;
}

/* Side by side, a long list makes the page taller than the window, and
   the pane sat at the top of it - click a row far down and the video was
   off screen. Sticky keeps it in view while the list scrolls past. It
   stops stretching to the row's height (that is what made it fill the
   whole page) and is capped to the window so its own scrollbar still
   works. Stacked on narrow screens it already has a fixed height. */
@media (min-width: 901px) {
	.box-detail-pane {
		position: sticky;
		top: var(--box-bars-h, 0px);
		align-self: start;
		max-height: calc(100vh - var(--box-bars-h, 0px));
		max-height: calc(100dvh - var(--box-bars-h, 0px));
	}
}

.box-detail-title {
	font-family: var(--box-display);
	font-size: calc(19px * var(--font-scale, 1));
	font-weight: 700;
	color: var(--box-ink);
	margin: 8px 0 3px;
	overflow-wrap: break-word;
}

.box-detail-meta {
	font-family: var(--box-mono);
	font-size: calc(11px * var(--font-scale, 1));
	color: var(--box-ink-faint);
	margin-bottom: 14px;
}

.box-detail-link {
	display: block;
	font-family: var(--box-mono);
	font-size: calc(12px * var(--font-scale, 1));
	color: var(--box-accent);
	background: var(--box-raised);
	border: 1px solid var(--box-rule);
	border-radius: 4px;
	padding: 8px 10px;
	margin-bottom: 14px;
	overflow-wrap: break-word;
}

.box-detail-badlink {
	font-size: calc(12px * var(--font-scale, 1));
	color: var(--box-warn);
	background: var(--box-raised);
	border: 1px solid var(--box-rule);
	border-left: 3px solid var(--box-warn);
	border-radius: 4px;
	padding: 8px 10px;
	margin-bottom: 14px;
	line-height: 1.5;
}

.box-detail-badlink-raw {
	font-family: var(--box-mono);
	font-size: calc(11px * var(--font-scale, 1));
	color: var(--box-ink-faint);
	margin-top: 5px;
	overflow-wrap: break-word;
}

.box-detail-body {
	font-size: calc(13.5px * var(--font-scale, 1));
	line-height: 1.6;
	color: var(--box-ink-muted);
	margin-bottom: 14px;
}

.box-detail-body p {
	/* A single Enter in a note is a line break; only blank lines make
	   a new paragraph. */
	white-space: pre-line;
	margin: 0 0 9px;
}

.box-code-block {
	margin-bottom: 14px;
}

.box-code-bar {
	display: flex;
	justify-content: flex-end;
	margin-bottom: 4px;
}

.box-chip-btn {
	font-family: var(--box-display);
	font-size: calc(9.5px * var(--font-scale, 1));
	font-weight: 700;
	letter-spacing: 1.2px;
	text-transform: uppercase;
	padding: 2px 8px;
	border-radius: 3px;
	border-width: 1px;
	border-style: solid;
	cursor: pointer;
}

.box-detail-code {
	font-family: var(--box-mono);
	font-size: calc(12px * var(--font-scale, 1));
	line-height: 1.55;
	background: var(--box-raised);
	border: 1px solid var(--box-rule);
	border-radius: 4px;
	padding: 10px 12px;
	color: var(--box-code-ink);

	/* Bounded by the pane, never by the text. */
	white-space: pre-wrap;
	overflow-wrap: anywhere;
}

/* Lines kept intact - the block scrolls inside itself, and its width
   still comes from the layout rather than from the longest line. */
.box-detail-code.is-nowrap {
	white-space: pre;
	overflow-wrap: normal;
	overflow-x: auto;
}

.box-tagrow {
	display: flex;
	flex-wrap: wrap;
	gap: 5px;
	margin-bottom: 14px;
}

.box-tag {
	font-size: calc(11px * var(--font-scale, 1));
	padding: 2px 9px;
	border-radius: 999px;
	background: var(--box-raised);
	border: 1px solid var(--box-rule);
	color: var(--box-ink-faint);
}

.box-detail-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	margin-top: 4px;
}

.box-detail-hint {
	font-family: var(--box-mono);
	font-size: calc(10.5px * var(--font-scale, 1));
	color: var(--box-ink-faint);
	margin-top: 10px;
}

/* ---------------- edit form ---------------- */

.box-field {
	display: block;
	margin-bottom: 11px;
}

.box-field-label {
	display: block;
	font-family: var(--box-display);
	font-size: calc(10px * var(--font-scale, 1));
	font-weight: 700;
	letter-spacing: 1.4px;
	text-transform: uppercase;
	color: var(--box-ink-faint);
	margin-bottom: 4px;
}

.box-input {
	width: 100%;
	font-family: inherit;
	font-size: calc(13px * var(--font-scale, 1));
	padding: 6px 8px;
	border: 1px solid var(--box-rule-strong);
	border-radius: 4px;
	background: var(--box-raised);
	color: var(--box-ink);
}

.box-input:focus {
	border-color: var(--box-accent);
	outline: none;
}

/* The core stylesheet turns off resizing and hides overflow on every
   textarea, which makes a long note unusable. Put both back. */
.box-textarea {
	resize: vertical;
	overflow: auto;
	line-height: 1.55;
	min-height: 90px;
}

.box-textarea-code {
	font-family: var(--box-mono);
	font-size: calc(12px * var(--font-scale, 1));
	white-space: pre-wrap;
	overflow-wrap: anywhere;
}

/* ---------------- player dock ---------------- */

/* Sits under the workspace and above the status bar, full width. It is
   never re-rendered and never re-parented: both players inside it stop
   dead if they are moved, so this element is created once by the markup
   and only ever gains and loses .hidden. */
.box-player {
	display: flex;
	flex-direction: column;
	border-bottom: 1px solid var(--box-rule);
	background: var(--box-surface);
}

/* A cap rather than a fixed height, so a short window still gets a
   usable strip of columns above it. */
.box-player-stage {
	position: relative;
	width: 100%;
	height: min(42vh, 360px);
	background: var(--box-video-ground);
}

/* Both players fill the stage and take turns being hidden. Absolute so
   the stage keeps its height while one of them is away, which stops the
   page jolting every time a box switches from a video to a file. */
.box-player-slot,
.box-player-file,
.box-player-stage iframe {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	border: 0;
}

/* Letterboxed rather than cropped. A music video that has been through
   three uploads is rarely the shape you expect. */
.box-player-file {
	object-fit: contain;
	background: var(--box-video-ground);
}

.box-player-bar {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 6px;
	padding: 8px 4px;
}

/* Takes the slack so Close lands on the right, and truncates instead of
   wrapping the bar onto a second line - the same problem the status bar
   has, solved the same way. */
.box-player-now {
	flex: 1 1 auto;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	font-family: var(--box-mono);
	font-size: calc(11px * var(--font-scale, 1));
	color: var(--box-ink-muted);
	font-variant-numeric: tabular-nums;
}

/* Small and Medium, from Settings. 16:9 because YouTube is, and never
   wider than the space it is given, so Medium on a narrow window just
   becomes Fit. Fit is the cap rule on the stage above. */
.box-player[data-size="small"] .box-player-stage,
.box-player[data-size="medium"] .box-player-stage {
	height: auto;
	aspect-ratio: 16 / 9;
	margin-inline: auto;
}

.box-player[data-size="small"] .box-player-stage {
	width: min(320px, 100%);
}

.box-player[data-size="medium"] .box-player-stage {
	width: min(640px, 100%);
}

/* ---------------- player beside the boxes ---------------- */

/* Wide screens only - a phone has no room beside anything, so there the
   player stays underneath and its Move button is hidden.

   The player is never moved to get there (see the dock note above): the
   app turns into a grid instead, and the player takes the cell beside
   the workspace. Only while it is showing, so a closed player leaves
   the page exactly as it always was. Search results share the
   workspace's cell, because the two take turns. */
@media (min-width: 901px) {
	.box-app:has(> .box-player[data-side="right"]:not(.hidden)) {
		display: grid;
		grid-template-columns: minmax(0, 1fr) auto;
		grid-template-rows: auto auto 1fr auto auto;
		grid-template-areas:
			"bars bars"
			"handover handover"
			"work player"
			"status status"
			"note note";
	}

	.box-app > .box-bars { grid-area: bars; }
	.box-app > .box-handover { grid-area: handover; }
	.box-app > .box-workspace,
	.box-app > .box-results { grid-area: work; }
	.box-app > .box-player { grid-area: player; }
	.box-app > .box-status { grid-area: status; }
	.box-app > .box-share-note { grid-area: note; }

	/* The column is the player's own width, so the boxes get the rest.
	   Capped against the window so Medium cannot squeeze them out. */
	.box-player[data-side="right"] {
		width: clamp(320px, 40vw, 960px);
		border-left: 1px solid var(--box-rule);

		/* Floats like the detail pane: in a long list the player stays in
		   view instead of waiting at the top of the page. Sticky moves
		   nothing in the DOM, so the video never restarts. */
		position: sticky;
		top: var(--box-bars-h, 0px);
		align-self: start;
	}

	.box-player[data-side="right"][data-size="small"] {
		width: 320px;
	}

	.box-player[data-side="right"][data-size="medium"] {
		width: min(640px, 50vw);
	}

	/* Fit beside is the column's full width at 16:9, with the buttons
	   straight under it rather than under a tall black box. */
	.box-player[data-side="right"] .box-player-stage {
		height: auto;
		aspect-ratio: 16 / 9;
	}
}

@media (max-width: 900px) {
	.box-player-side {
		display: none;
	}
}

/* ---------------- search results ---------------- */

.box-results {
	flex: 1 1 auto;
	min-height: 380px;
	overflow-y: auto;
	border-bottom: 1px solid var(--box-rule);
	padding: 4px 0 10px;
}

.box-results-head {
	font-family: var(--box-display);
	font-size: calc(10px * var(--font-scale, 1));
	font-weight: 700;
	letter-spacing: 1.6px;
	text-transform: uppercase;
	color: var(--box-ink-faint);
	padding: 10px 10px 8px;
	border-bottom: 1px solid var(--box-rule);
}

.box-result {
	display: flex;
	align-items: flex-start;
	gap: 9px;
	width: 100%;
	text-align: left;
	background: none;
	border: 0;
	border-bottom: 1px solid var(--box-rule);
	padding: 9px 10px;
	cursor: pointer;
	font-family: inherit;
}

.box-result:hover {
	background: var(--box-accent-soft);
}

.box-result .box-kind {
	margin-top: 2px;
}

.box-result-text {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
}

.box-result-title {
	font-size: calc(13.5px * var(--font-scale, 1));
	font-weight: 600;
	color: var(--box-ink);
}

.box-result-where {
	font-family: var(--box-mono);
	font-size: calc(10.5px * var(--font-scale, 1));
	color: var(--box-ink-faint);
}

.box-result-snippet {
	font-size: calc(12px * var(--font-scale, 1));
	color: var(--box-ink-muted);
	line-height: 1.45;
}

/* ---------------- status bar ---------------- */

.box-status {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px 20px;
	padding: 8px 4px 4px;
	font-family: var(--box-mono);
	font-size: calc(11px * var(--font-scale, 1));
	color: var(--box-ink-faint);
	font-variant-numeric: tabular-nums;
}

.box-status-gauges {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px 20px;
}

.box-status-item {
	display: inline-flex;
	align-items: center;
	gap: 7px;
}

.box-message {
	color: var(--box-ink-muted);
}

.box-gauge {
	display: inline-block;
	width: 74px;
	height: 6px;
	border-radius: 3px;
	background: var(--box-rule);
	overflow: hidden;
}

.box-gauge i {
	display: block;
	height: 100%;
	background: var(--box-ok);
}

.box-gauge i.is-close {
	background: var(--box-warn);
}

.box-gauge i.is-over {
	background: var(--box-accent);
}

/* ---------------- dialogs ---------------- */

.box-import,
.box-share {
	width: min(680px, 92vw);
	border: 1px solid var(--box-rule-strong);
	border-radius: 6px;
	padding: 20px 22px;
	color: var(--box-ink);
	background: var(--box-ground);
}

.box-import::backdrop,
.box-share::backdrop {
	background: var(--box-backdrop);
}

.box-import-title,
.box-share-title {
	font-family: var(--box-display);
	font-size: calc(20px * var(--font-scale, 1));
	font-weight: 700;
	color: var(--box-accent);
	letter-spacing: 2px;
	text-transform: uppercase;
	margin-bottom: 4px;
}

.box-import-where,
.box-share-what {
	font-size: calc(12.5px * var(--font-scale, 1));
	color: var(--box-ink-muted);
	margin-bottom: 14px;
}

/* The Import dialog from the gear: the text, then how to split it and
   a file, side by side when there is room. */
.box-import-row {
	display: flex;
	flex-wrap: wrap;
	gap: 16px;
}

.box-import-row .box-field {
	flex: 1 1 220px;
}

.box-import-format {
	width: 100%;
	font-family: inherit;
	font-size: calc(13px * var(--font-scale, 1));
	padding: 6px 8px;
	border: 1px solid var(--box-rule-strong);
	border-radius: 4px;
	background: var(--box-raised);
}

.box-import-file {
	font-size: calc(12px * var(--font-scale, 1));
	color: var(--box-ink-muted);
}

/* ---------------- sharing ---------------- */

/* A box's Share dialog, narrower than the shared rule above - it holds
   link cards, not a page of pasted text. The list inside is
   js/share/linkList.js, and its share-* classes are styled here the way
   calendar.css styles them for a calendar. */
.box-share {
	width: min(560px, 92vw);
}

/* The shared styles set display on a great many things, and an element
   that sets its own display ignores the hidden attribute without this -
   the list's error line starts hidden. */
.box-share [hidden] {
	display: none !important;
}

.box-share-body,
.box-share-body .share-links {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.box-share-body {
	margin-bottom: 14px;
}

.share-link {
	display: flex;
	flex-direction: column;
	gap: 6px;
	padding: 10px 12px;
	border: 1px solid var(--box-rule);
	border-radius: 4px;
	background: var(--box-raised);
}

.share-link-what {
	font-size: calc(12px * var(--font-scale, 1));
	color: var(--box-ink-muted);
}

.share-link-what strong {
	color: var(--box-ink);
}

/* The address, on show and selectable - so it can be copied by hand
   where a page is not allowed to copy for you. */
.share-link-url {
	width: 100%;
	min-width: 0;
	font-family: var(--box-mono);
	font-size: calc(12px * var(--font-scale, 1));
	padding: 5px 7px;
	border: 1px solid var(--box-rule-strong);
	border-radius: 4px;
	background: var(--box-ground);
	color: var(--box-ink);
}

.share-link-actions,
.share-make {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 6px;
}

.box-share-hint {
	margin: 0;
	font-size: calc(12.5px * var(--font-scale, 1));
	color: var(--box-ink-muted);
}

.box-share-error {
	margin: 0;
	font-size: calc(12.5px * var(--font-scale, 1));
	color: var(--box-warn);
}

/* On the page a share link opens: where the box came from. */
.box-share-note {
	margin: 6px 4px 0;
	font-size: calc(12px * var(--font-scale, 1));
	color: var(--box-ink-faint);
}

/* A box that has a link, marked in its row - so what is shared is never
   a surprise. */
.box-shared-mark {
	flex: none;
	color: var(--box-accent);
	font-size: calc(11px * var(--font-scale, 1));
}

/* ---------------- narrow screens ---------------- */

@media (max-width: 900px) {
	.box-workspace {
		grid-template-columns: minmax(0, 1fr);
		grid-template-rows: 1fr auto;
		height: auto;
	}

	.box-splitter {
		display: none;
	}

	.box-strip {
		height: 46vh;
		min-height: 260px;
		border-bottom: 1px solid var(--box-rule);
	}

	.box-detail-pane {
		max-height: 50vh;
	}

	.box-col {
		min-width: calc(130px * var(--font-scale, 1));
		max-width: calc(240px * max(1, var(--font-scale, 1)));
	}

	/* Repeated, because the rule above outranks the wide one. */
	.box-col.is-wide {
		max-width: 85vw;
	}

	.box-search {
		flex-basis: 100%;
		order: 5;
	}
}

/* Shown while auth is still deciding, and removed the moment it has.
   The app itself ships hidden - see the note in myBoxes.html - so this is
   the only thing on the page during that window. */
.box-checking {
	padding: 18px 12px;
	color: var(--box-ink-faint);
	font-size: calc(13px * var(--font-scale, 1));
}
