/* Everything Bootstrap does not already do. Deliberately short. */

/*
 * How wide a page gets. Loaded after Bootstrap and equally specific, so this
 * beats `.container`'s own ceiling rather than adding to it — one number, not a
 * set of breakpoints.
 *
 * 90rem is 1440px, chosen against a 1080p desktop: wide enough for a list with
 * a dozen columns and for fields sitting side by side, with a gutter left over
 * so the page still reads as a page. Bootstrap's own maximum is 1320px, which
 * was drawn for narrower screens than the ones this is used on.
 *
 * Narrower is still a per-page decision — the delete confirmations set their own
 * width inline, because a question with two buttons does not want a metre of it.
 */
.page-shell {
	max-width: 90rem;
}

.signin-shell {
	min-height: 100vh;
	display: grid;
	place-items: center;
	padding: 1.5rem;
}

/*
 * The sign-in card centres everything — except what somebody types into.
 *
 * Centred text in an input moves as it is typed: the caret sits in the middle
 * and both ends drift outwards with every character, which is a small
 * unpleasantness on the one field on this page anybody has to be careful with.
 * Its label is centred; its contents are not.
 */
.signin-shell .form-control {
	text-align: start;
}

/* Dashboard module tiles. */
.module-tile {
	text-decoration: none;
	color: inherit;
	transition: border-color .15s ease-in-out;
}

.module-tile:hover {
	border-color: var(--bs-primary);
}

/* Keep row actions on one line even when a table scrolls. */
.row-actions {
	white-space: nowrap;
}

/*
 * The module tabs live in the top bar, but an active tab belongs to the page
 * below it. Bootstrap fills it with --bs-body-bg, which is the bar's own colour
 * here, so the tab would merge into the bar. Pointing both the fill and the
 * bottom border at the page colour makes the active tab continuous with the
 * content instead — which is the whole idea of a tab.
 */
.navbar .nav-tabs {
	--bs-nav-tabs-link-active-bg: var(--bs-tertiary-bg);
	--bs-nav-tabs-link-active-border-color: var(--bs-border-color) var(--bs-border-color) var(--bs-tertiary-bg);
}

/*
 * The signed-in person's avatar (XIV-77): initials in a circle, on a colour
 * derived from their email in App\Twig\Avatar and handed over as a hue.
 *
 * **The hue is the only thing that varies.** Saturation and lightness are fixed
 * here so the white initials keep their contrast whatever colour somebody's
 * email happens to hash to — 32% lightness is chosen against the worst case,
 * which is yellow at hue 60 and clears 4.5:1 with a little to spare. A colour
 * chosen freely per person would eventually choose a pale one and put white text
 * on it.
 *
 * One treatment in both themes rather than two: a filled dark circle reads
 * against the light page and against the dark one, and a second palette would be
 * a second thing to keep legible for no gain.
 */
/*
 * Deliberately taller than the button beside it. It was 1.5rem while it lived
 * *inside* that button, where it had to be smaller than its container; matching
 * the button's height afterwards was the same timidity one step on. The avatar
 * is the thing a person looks for to find themselves in the page, so it is the
 * biggest thing in this corner and the button is what sits beside *it*.
 *
 * The navbar's own padding is what stops this driving the bar's height — at
 * 2.5rem the circle is still shorter than the row the brand and the tabs
 * already make.
 */
.avatar {
	inline-size: 2.5rem;
	block-size: 2.5rem;
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border-radius: 50%;
	background: hsl(var(--avatar-hue, 0) 45% 32%);
	color: #fff;
	font-size: .95rem;
	font-weight: 600;
	line-height: 1;
}

/*
 * A name has no length limit and the bar has a width, so somebody called
 * "Alexander von Habsburg-Lothringen" truncates rather than pushing the module
 * tabs onto another row. The circle beside it never shrinks — it is two
 * characters and the one part of this that stays readable at any width.
 */
.topbar-name {
	max-width: 14rem;
}

/*
 * The record timeline (XIV-3).
 *
 * One line per entry, with the changes behind a native <details> — no
 * JavaScript, and open to the keyboard for free. What is styled here is only
 * what the browser gets wrong on its own: the disclosure marker sits on its own
 * line unless the summary is made a flex row, and Safari needs the vendor
 * pseudo-element to accept a marker at all.
 */
.history-entry > summary {
	cursor: pointer;
	list-style-position: inside;
}

.history-entry > summary::-webkit-details-marker {
	display: none;
}

/*
 * An entry with nothing to open — a record being created — has no marker, so its
 * time would start where the others' markers do. This keeps the column of times
 * straight either way.
 */
.history-entry-plain {
	padding-left: 1.15em;
}

.history-section > summary {
	cursor: pointer;
}

/*
 * What points at this record (§7.6), closed until asked for.
 *
 * The same treatment the timeline gets above and for the same reason: the
 * marker sits on its own line unless the summary is made to lay out inline, and
 * Safari needs the vendor pseudo-element before it will accept one at all.
 */
.linked-group > summary {
	cursor: pointer;
	list-style-position: inside;
}

.linked-group > summary::-webkit-details-marker {
	display: none;
}

/*
 * Collection rows carry a position (XIV-21).
 *
 * Narrow, and out of the way: it is a number about the list rather than a value
 * of the row, so it should not read as another field to fill in.
 */
.row-position-cell {
	float: left;
	width: 4rem;
	margin-right: .75rem;
}

.row-of-collection::after {
	content: "";
	display: block;
	clear: both;
}

/*
 * The email preview (XIV-39).
 *
 * A frame with a fixed height rather than one that grows to its content: an
 * iframe cannot be measured from outside without scripting, and the message is
 * meant to be scrolled the way it would be in a mail client anyway. Tall enough
 * that an ordinary confirmation is read without touching the scrollbar.
 */
.mail-preview {
	height: 32rem;
	background: #fff;
}

/*
 * A follow-up's note, as it was typed (XIV-82).
 *
 * A note is prose somebody wrote into a textarea, so the line breaks in it are
 * theirs. HTML collapses whitespace by default, which would silently reflow a
 * two-line note into one and make a list of points read as a run-on sentence.
 * `pre-wrap` rather than `pre`: the breaks are kept and long lines still wrap to
 * the card, which is the only combination that survives a narrow screen.
 */
.follow-up-note {
	white-space: pre-wrap;
}

/*
 * A follow-up's priority, as a bar down its leading edge (XIV-84).
 *
 * Bootstrap gets *almost* all the way here on its own — `border-start border-4
 * border-danger` — and the gap is the colour. `border-{color}` sets
 * `border-color` on all four sides at once, because Bootstrap has no per-side
 * colour utility. On a card, which already has an outline, that tints the whole
 * outline rather than the one edge; on a flush list item it repaints the hairline
 * separators between rows in the priority colour. Both were the wrong picture,
 * and neither is reachable by adding more utilities.
 *
 * So the colour arrives as a custom property the template sets from
 * `follow_up_tone()` — the same single mapping both screens already draw their
 * badges from — and only the left edge reads it. Pointing at `--bs-info` and its
 * siblings rather than at a hex is what keeps this right in the dark theme:
 * Bootstrap 5.3 redefines those under `[data-bs-theme=dark]`, so the bar follows
 * without this file knowing there are two themes.
 *
 * `!important` deliberately, and it is the same reason Bootstrap's own border
 * utilities carry it. `.list-group-flush > .list-group-item` sets `border-width:
 * 0 0 1px` at a specificity this cannot reach with one class, so without it the
 * left edge is zero pixels wide and the rule silently does nothing.
 */
.follow-up-priority {
	border-left: 4px solid var(--follow-up-tone, var(--bs-border-color)) !important;
}

/*
 * The modules cell on the tenant list, kept to a column rather than a paragraph
 * (XIV-95).
 *
 * The cell now holds a list — one module per line, with its record count and, if
 * the registry and the customer's database disagree about it, a short phrase
 * saying so. That is much more text than the row of badges it replaced, and a
 * table cell with no width of its own will happily take as much of the table as
 * its longest line asks for: the eight columns beside it would be squeezed into
 * the remainder, and the two dates — which are fixed-width and non-negotiable —
 * would wrap.
 *
 * `min-width` as well as `max-width` because both failures are real. Without the
 * maximum a customer with a long module name stretches the column; without the
 * minimum a customer with one short one lets it collapse to the width of
 * `contact`, and the rows then no longer line up with each other, which is the
 * thing that makes a table readable at a glance in the first place.
 *
 * A width rather than `text-overflow: ellipsis`, deliberately. Truncation would
 * hide exactly the phrase that says two sources disagree, and hiding it behind a
 * hover is what this ticket removed from the cell next door.
 */
.module-cell {
	min-width: 12rem;
	max-width: 18rem;
}

/*
 * The order box beside each widget in the dashboard picker (XIV-66).
 *
 * A number input with nothing said about it fills the flex row it sits in, which
 * on the account page puts a five-character box next to a two-word label and
 * makes the label the thing that looks squeezed. Fixed and small, because what it
 * holds is a position in a list of at most a handful of cards — three digits is
 * already more room than the widget count could justify.
 *
 * A class rather than an inline style so that the two screens drawing this
 * partial cannot end up disagreeing about it, which is the whole reason the
 * partial is shared.
 */
.widget-position {
	width: 5rem;
	flex: 0 0 auto;
}

/*
 * A formatted field, rendered (XIV-131).
 *
 * Almost nothing, and the almost is the interesting part. What comes out of
 * CommonMark is ordinary semantic markup — headings, paragraphs, lists, tables —
 * and Bootstrap already styles every one of those, so a block that set its own
 * type would be a second opinion about how this application looks, held in one
 * corner of one page. The two rules here are the two places where the *default*
 * is wrong specifically because the markup is inside a card rather than being the
 * page.
 *
 * **Headings shrink.** An `<h2>` a customer typed inside a field is a heading
 * within their text, not a heading of the record page — and drawn at the page's
 * own h2 size it is bigger than the record's title, which makes a note look like
 * it has taken over. `em` rather than `rem` so the scale follows whatever context
 * it lands in.
 *
 * **The last block loses its margin.** Every block element here carries a bottom
 * margin, which on the final one is space inside the container that nothing is
 * separating from anything.
 */
.markdown-body > :last-child {
	margin-bottom: 0;
}

.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
	font-size: 1.1em;
	font-weight: 600;
}

/*
 * And the preview under the textarea somebody is typing into.
 *
 * It has to read as *output* rather than as more of the form, or the eye takes
 * it for another control and looks for the label. A dashed edge and the muted
 * background say "this is what that will look like" without a heading having to
 * say it — the word above it is one line and does the rest.
 */
.markdown-preview {
	border: 1px dashed var(--bs-border-color);
	border-radius: var(--bs-border-radius);
	padding: 0.75rem;
	background-color: var(--bs-tertiary-bg);
}

.markdown-preview-label {
	font-size: 0.75rem;
	text-transform: uppercase;
	letter-spacing: 0.03em;
	color: var(--bs-secondary-color);
}

/*
 * The box a record's trend chart is drawn into (XIV-121).
 *
 * Chart.js sizes a canvas from its container, and a canvas with no container
 * height either collapses to nothing or — with `maintainAspectRatio` left on —
 * derives one from its width. Neither is right here: this card lives in a column
 * that is a third of the page on a laptop and the whole of it on a phone, so an
 * aspect ratio would make the same chart a letterbox on one and a square on the
 * other, and the *shape of the line* is the entire content of a trend.
 *
 * A fixed height is therefore the honest answer, and it is a small one on
 * purpose. This is a card beside a record rather than a report: what it has to
 * show is whether a number went up, down or nowhere, which reads perfectly at
 * ten lines of text and would push the timeline below it off the screen at
 * twenty.
 *
 * `position: relative` because Chart.js's responsive mode measures the parent
 * and then absolutely positions the canvas inside it; without it the canvas
 * measures the card and grows on every re-render, which is a real Chart.js
 * behaviour and not a hypothetical one.
 */
.trend-chart {
	position: relative;
	height: 10rem;
}

/*
 * Arranging a form by moving the fields (XIV-165).
 *
 * Three states worth drawing and nothing else. The grip says the row can be
 * picked up, and it is the only thing on the row that can start a drag, so it
 * gets the cursor that promises that; `grabbing` while the pointer is down is
 * the feedback that tells somebody the gesture took, on the half-second before
 * anything has moved far enough to see.
 *
 * `.arrange-dragging` is the row's own slot while the copy of it is under the
 * cursor. It is drawn as an empty outline rather than as a faded row, because
 * what it is saying is "this is where it lands", and a faded row says "this is
 * the row", which it is not: the row is the thing following the pointer.
 *
 * `.arrange-in-flight` is that copy. A `<tr>` taken out of a table has no layout
 * of its own, so `display: table` is what stops it collapsing into a stripe of
 * overlapping text while it is being carried. The widths of its cells will not
 * match the table underneath it and that is accepted: it is a label under the
 * cursor for as long as a gesture lasts, not a preview of the result.
 */
.arrange-handle {
	cursor: grab;
	color: var(--bs-secondary-color);
	padding: 0 0.25rem;
	touch-action: none;
}

.arrange-handle:active {
	cursor: grabbing;
}

.arrange-table tr.arrange-dragging > * {
	background-color: var(--bs-tertiary-bg);
	color: transparent;
}

.arrange-table tr.arrange-dragging {
	outline: 2px dashed var(--bs-primary-border-subtle);
	outline-offset: -2px;
}

.arrange-table tr.arrange-in-flight {
	display: table;
	background-color: var(--bs-body-bg);
	box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
	opacity: 0.95;
}

/*
 * The heading a field is dragged under. A row that is a label rather than a
 * record, so it loses the table's hover and its own borders and keeps the
 * shading, which is what makes the run below it read as belonging to it.
 */
.arrange-table tr.arrange-heading > th {
	font-weight: 600;
	border-bottom-width: 2px;
}
