/*
 * Hand-written CSS, no framework loaded from a CDN.
 *
 * A clinic with no internet must still be able to use the application, and a stylesheet
 * fetched from someone else's server would leave the interface unusable exactly when
 * things are already going wrong. Everything here is served from the application itself —
 * the typeface included, which is why Nunito sits in /fonts rather than on Google's servers.
 *
 * The values at the top are the Kanuve design system's tokens, under the same names. The
 * palette is taken from the logo and the axolotl: warm paper, the pink of its body and
 * gills, the grey-blue of the tail, and the black ink of the lettering. Pink is the brand
 * and the navigation; the blue is for actions, so a button never looks like an alarm.
 */

/* --- The typeface --- */

@font-face {
	font-family: "Nunito";
	src: url("../fonts/nunito-latin-wght-normal.woff2") format("woff2");
	font-weight: 200 1000;
	font-style: normal;
	font-display: swap;
}

/* --- Tokens --- */

:root {
	/* Grounds */
	--paper: #faf6f1;
	--surface: #ffffff;
	--surface-sunken: #f5efe9;
	--surface-hover: #fcf7f3;

	/* Ink and lines */
	--ink: #2a2124;
	--ink-muted: #6b5d62;
	--line: #ebe2db;
	--line-strong: #ddd0c8;
	--line-control: #9f8c85;

	/* The axolotl */
	--rose-50: #fdf2f1;
	--rose-100: #fbe4e2;
	--rose-200: #f6cfcb;
	--rose-400: #e98a80;
	--rose-600: #b4505a;
	--rose-700: #953c48;

	/* The tail */
	--tide-50: #f0f5f7;
	--tide-100: #e1ecf0;
	--tide-300: #a6c2cc;
	--tide-600: #3e6a7c;
	--tide-700: #2d5566;
	--tide-800: #203f4c;

	/* What happened */
	--ok-bg: #e5f2e9;
	--ok-ink: #2a6b44;
	--warn-bg: #fcefd9;
	--warn-ink: #875510;
	--danger-bg: #fde4dd;
	--danger-ink: #a3321f;
	--danger-line: #efb6a6;
	--danger-strong: #82271a;
	--focus: var(--tide-600);

	/* The appointment palette: a light fill and a darker edge, the ink reading on all */
	--appt-blue-fill: #e3edf5;
	--appt-blue-edge: #1c6e8c;
	--appt-green-fill: #e4f2e8;
	--appt-green-edge: #2f7d4f;
	--appt-amber-fill: #fbf0dc;
	--appt-amber-edge: #9a6a12;
	--appt-red-fill: #fbe6e6;
	--appt-red-edge: #a33a3a;
	--appt-purple-fill: #ece7f6;
	--appt-purple-edge: #6a4fa3;
	--appt-teal-fill: #e0f1f0;
	--appt-teal-edge: #2b7a72;
	--appt-pink-fill: #fbe7ef;
	--appt-pink-edge: #a8447a;
	--appt-grey-fill: #eceff1;
	--appt-grey-edge: #5b6b7a;

	/* How the animal behaves, from worst to best */
	--behaviour-very-bad-bg: #fbe6e6;
	--behaviour-very-bad-ink: #8f2626;
	--behaviour-bad-bg: #fdeee6;
	--behaviour-bad-ink: #93441a;
	--behaviour-good-bg: #eaf4ec;
	--behaviour-good-ink: #2f6b45;
	--behaviour-very-good-bg: #e2f2e7;
	--behaviour-very-good-ink: #1f6b3a;

	/* Type */
	--font-sans: "Nunito", "Segoe UI", system-ui, -apple-system, sans-serif;

	/* Spacing */
	--space-1: 4px;
	--space-2: 8px;
	--space-3: 12px;
	--space-4: 16px;
	--space-5: 20px;
	--space-6: 24px;
	--space-8: 32px;
	--space-10: 40px;

	/* Radii */
	--radius-sm: 6px;
	--radius-md: 10px;
	--radius-lg: 16px;
	--radius-pill: 999px;

	/* Shadows: warm, never grey */
	--shadow-sm: 0 1px 2px rgba(74, 44, 40, .06);
	--shadow-md: 0 6px 18px rgba(74, 44, 40, .09);
	--shadow-lg: 0 18px 40px rgba(74, 44, 40, .16);

	/* Layout */
	--sidebar-width: 224px;
	--sidebar-rail: 64px;
	--content-max: 1180px;
}

* {
	box-sizing: border-box;
}

html {
	-webkit-text-size-adjust: 100%;
	scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}

	*, *::before, *::after {
		transition: none !important;
	}
}

body {
	margin: 0;
	font-family: var(--font-sans);
	font-size: .9375rem;
	background: var(--paper);
	color: var(--ink);
	line-height: 1.55;
	-webkit-font-smoothing: antialiased;
}

body.centered {
	min-height: 100vh;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 1rem;
}

a {
	color: var(--tide-700);
	text-underline-offset: .15em;
}

a:hover {
	color: var(--tide-800);
}

h1, h2, h3 {
	line-height: 1.25;
	letter-spacing: -.005em;
}

/*
 * One focus ring for everything that can be tabbed to: solid, in the tail's blue, and
 * well clear of every ground it lands on.
 */
:focus-visible {
	outline: 2px solid var(--focus);
	outline-offset: 2px;
}

/* --- Icons --- */

/*
 * Every icon is a <use> into /img/icons.svg. The strokes are drawn in currentColor, so an
 * icon takes the colour of the words beside it and needs no variant of its own.
 */
.icon {
	width: 1.25rem;
	height: 1.25rem;
	flex: none;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.8;
	stroke-linecap: round;
	stroke-linejoin: round;
	vertical-align: -.25em;
}

.icon-sm {
	width: 1rem;
	height: 1rem;
}

/* --- Login --- */

/*
 * Two halves on a screen wide enough: the axolotl saying hello on the left and the form
 * on the right. On a phone the welcome shrinks to the logo and a smaller axolotl above
 * the form, so the fields are still where the thumb is.
 */
.login {
	min-height: 100vh;
	display: grid;
	grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
}

.login-welcome {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: var(--space-6);
	padding: var(--space-10);
	background: var(--rose-50);
	border-right: 1px solid var(--rose-100);
	overflow: hidden;
}

/* A soft disc behind the axolotl, cut from the same pink as its body. */
.login-welcome::before {
	content: "";
	position: absolute;
	width: 34rem;
	height: 34rem;
	border-radius: 50%;
	background: var(--rose-100);
	top: 50%;
	left: 50%;
	transform: translate(-50%, -46%);
}

.login-logo {
	position: relative;
	width: min(320px, 70%);
	height: auto;
}

.login-mascot {
	position: relative;
	width: min(360px, 80%);
	height: auto;
}

.login-main {
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--space-10) var(--space-6);
}

.card {
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--radius-lg);
	padding: 2.25rem 2rem;
	width: 100%;
	max-width: 400px;
	box-shadow: var(--shadow-md);
}

.card h1 {
	margin: 0;
	font-size: 1.6rem;
	font-weight: 800;
	color: var(--ink);
}

.subtitle {
	margin: .25rem 0 1.5rem;
	color: var(--ink-muted);
	font-size: .95rem;
}

/* "¿Has olvidado tu contraseña?" and the way back, under the card's button. */
.login-links {
	margin: 1.25rem 0 0;
	text-align: center;
	font-size: .92rem;
}

/* An error under a box of the login card, closer to its box than to the next label. */
.card .login-field-error {
	margin: -.6rem 0 1rem;
}

.card .hint-block {
	margin: 0 0 .5rem;
	color: var(--ink-muted);
}

/* A link that does what the card's button would, and looks it. */
.card .login-button {
	width: 100%;
	height: 2.9rem;
	font-size: 1rem;
	text-decoration: none;
}

@media (max-width: 860px) {
	.login {
		grid-template-columns: 1fr;
	}

	.login-welcome {
		flex-direction: row;
		justify-content: center;
		gap: var(--space-4);
		padding: var(--space-5) var(--space-4) var(--space-4);
		border-right: none;
		border-bottom: 1px solid var(--rose-100);
	}

	.login-welcome::before {
		display: none;
	}

	.login-logo {
		width: 150px;
	}

	.login-mascot {
		width: 96px;
	}

	.login-main {
		align-items: flex-start;
		padding: var(--space-6) var(--space-4) var(--space-10);
	}
}

/* --- Forms --- */

label {
	display: block;
	margin-bottom: .35rem;
	font-size: .85rem;
	font-weight: 700;
}

/*
 * Checkboxes and radios are left out of width:100%: they are not text boxes, and
 * stretching one across its container drew a 180-pixel-wide tick box next to the
 * search field.
 */
/*
 * .visually-hidden is excluded, and not for tidiness. That class sets width:1px to take
 * an input out of sight while leaving it reachable by keyboard and by a label's click —
 * which is how the photo upload works. This selector is more specific than the class, so
 * it was winning and stretching that hidden input to the full width of the screen: on a
 * phone it stuck out past the right edge and slid the whole animal's file sideways.
 */
/*
 * NOTE ON SPECIFICITY, because this has caught three separate screens now. The three
 * :not() clauses count as classes, so this rule weighs (0,3,1) and beats anything
 * written as ".something input" or ".something input[type=x]". A narrower box needs the
 * same three clauses repeated, or it silently comes out full width.
 */
input:not([type="checkbox"]):not([type="radio"]):not(.visually-hidden), select, textarea {
	width: 100%;
	line-height: 1.5;
	padding: .55rem .75rem;
	border: 1px solid var(--line-control);
	border-radius: var(--radius-md);
	font-size: 1rem;
	font-family: inherit;
	background: var(--surface);
	color: var(--ink);
	transition: border-color .12s ease, box-shadow .12s ease;
}

input::placeholder, textarea::placeholder {
	color: var(--ink-muted);
	opacity: .8;
}

/*
 * One stated height for every single-line control, because padding alone does not get
 * them level. A <select> reserves room for its arrow and an <input type=date> for its
 * calendar icon, so the same padding and font came out 41.58, 44.92 and 42.92 pixels —
 * a three-pixel stagger that is obvious the moment they sit in a row.
 *
 * Checkboxes and radios are excluded: they are not text boxes and stretching them to
 * 2.7rem would draw two enormous squares. Textarea is excluded because it is meant to
 * be several lines tall and resizable.
 */
input:not([type="checkbox"]):not([type="radio"]):not(.visually-hidden),
select {
	height: 2.7rem;
}

textarea {
	resize: vertical;
}

input[type="checkbox"], input[type="radio"] {
	width: 1.1rem;
	height: 1.1rem;
	accent-color: var(--tide-700);
}

input:focus, select:focus, textarea:focus {
	outline: 2px solid var(--focus);
	outline-offset: 1px;
	border-color: var(--focus);
}

.input-error {
	border-color: var(--danger-ink);
	background: var(--danger-bg);
}

.card input {
	margin-bottom: 1rem;
}

button {
	padding: .6rem 1.1rem;
	background: var(--tide-700);
	color: #fff;
	border: none;
	border-radius: var(--radius-md);
	font-size: .95rem;
	font-family: inherit;
	font-weight: 700;
	cursor: pointer;
	transition: background-color .12s ease;
}

button:hover {
	background: var(--tide-800);
}

.card button {
	width: 100%;
	height: 2.9rem;
	margin-top: .5rem;
	font-size: 1rem;
}

.form {
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--radius-lg);
	padding: 1.75rem;
	max-width: 900px;
	box-shadow: var(--shadow-sm);
}

/*
 * Section headings inside a form long enough to need dividing up. The rule that would
 * otherwise apply is the browser's, which renders an h2 the same size as the page title
 * above it and flattens the hierarchy.
 */
.form h2 {
	font-size: 1.05rem;
	font-weight: 800;
	margin: .5rem 0 1.25rem;
	padding-top: 1.25rem;
	border-top: 1px solid var(--line);
}

.form-row {
	display: flex;
	gap: 1rem;
	flex-wrap: wrap;
}

/*
 * position:relative so a .hint can hang out of the box below its input — see .hint for
 * why that matters to the row above it.
 */
.field {
	position: relative;
	flex: 1 1 220px;
	margin-bottom: 1rem;
	min-width: 0;
}

.field-wide {
	flex: 3 1 320px;
}

.field-narrow {
	flex: 0 1 140px;
}

.checkbox-field label {
	display: flex;
	align-items: center;
	gap: .5rem;
	font-weight: 600;
	margin-top: 1.6rem;
}

.checkbox-field input {
	width: auto;
}

/*
 * In the flow, taking up the room it needs.
 *
 * It used to be positioned absolutely so that a hint could not make its own field taller
 * than its neighbours. The price was that it was drawn on top of whatever came next: one
 * line reached 7px into the label below, and two lines landed across it. On a form where
 * several fields carry hints that is a page that looks broken.
 *
 * It can be in the flow here because .form-row aligns on stretch: every field is the
 * height of the row and its contents stack from the top, so one taller field leaves the
 * others' labels and inputs exactly where they were.
 */
.hint {
	display: block;
	font-size: .8rem;
	color: var(--ink-muted);
	margin-top: .3rem;
}

/*
 * The exception, and the reason the original rule existed. An .inline-form aligns on
 * flex-end so that a submit button with no label above it still lines up with the inputs
 * beside it — and there a hint in the flow makes its own field taller and shoves that
 * column's label and input above everybody else's. Visible on the dose form, where only
 * "Lote" carries one. There, and only there, it comes out of the flow.
 */
.inline-form .hint {
	position: absolute;
	top: 100%;
	left: 0;
}

/* Its display:block would otherwise win over [hidden], as with .field-error. */
.hint[hidden] {
	display: none;
}

/*
 * The lines about a vaccine chosen from the catalogue, under the dose form rather than
 * under its box: there the hints sit out of the flow, and "Lote" already has one. The
 * top margin collapses into the form's own and leaves that hint clear; nothing shows
 * while there is nothing to say.
 */
.catalogue-note {
	margin: 2rem 0 1.25rem;
}

.catalogue-note:not(:has(> :not([hidden]))) {
	display: none;
}

/* A hint that is a warning: the medicine chosen is not authorised for this animal. */
.hint-warn {
	color: var(--warn-ink);
	font-weight: 600;
}

.field-error {
	display: block;
	font-size: .82rem;
	color: var(--danger-ink);
	margin-top: .3rem;
	font-weight: 700;
}

/*
 * An error the page shows only when it applies, like the blank signature pad. The
 * display above outranks the hidden attribute, so without this it showed all along.
 */
.field-error[hidden] {
	display: none;
}

.form-actions {
	display: flex;
	/*
	 * On a narrow screen the actions move to the next line whole, rather than squeezing
	 * a button until its words stack three high. It only does anything when they do not
	 * fit, so a form with one button and a Cancel looks exactly as it did.
	 */
	flex-wrap: wrap;
	align-items: center;
	gap: 1rem;
	margin-top: .75rem;
	padding-top: 1.25rem;
	border-top: 1px solid var(--line);
}

.form-actions > button,
.form-actions > .button {
	white-space: nowrap;
}

.inline-form {
	display: flex;
	align-items: flex-end;
	gap: 1rem;
	flex-wrap: wrap;
	margin-bottom: 1.25rem;
}

.inline-form .field {
	margin-bottom: 0;
}

/*
 * A button beside a text box is the box's height, or the pair reads as two sizes. Written
 * before the pagination rules on purpose: the "go to page" box there is a smaller pair and
 * its own rule, coming later, wins.
 */
.inline-form button,
.inline-form .button,
.search button,
.day-nav .button {
	height: 2.7rem;
}

/* --- Messages --- */

/*
 * The icon goes in the padding rather than making the alert a flex row: alerts carry a
 * <strong> and a <span> in running text, and as flex items those came apart into columns.
 * The icon is a mask painted in currentColor, so it is always the colour of the words.
 */
.alert {
	position: relative;
	padding: .7rem .9rem .7rem 2.6rem;
	border-radius: var(--radius-md);
	font-size: .92rem;
	margin: 0 0 1rem;
	border: 1px solid transparent;
}

.alert::before {
	content: "";
	position: absolute;
	left: .85rem;
	top: .78rem;
	width: 1.15rem;
	height: 1.15rem;
	background: currentColor;
	-webkit-mask: var(--alert-icon) center / contain no-repeat;
	mask: var(--alert-icon) center / contain no-repeat;
}

.alert-error {
	background: var(--danger-bg);
	color: var(--danger-ink);
	border-color: var(--danger-line);
	--alert-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.3 3.9 2.4 17.6A2 2 0 0 0 4.1 20.5h15.8a2 2 0 0 0 1.7-2.9L13.7 3.9a2 2 0 0 0-3.4 0Z'/%3E%3Cpath d='M12 9.5v4M12 17h.01'/%3E%3C/svg%3E");
}

.alert-ok {
	background: var(--ok-bg);
	color: var(--ok-ink);
	--alert-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='m8.5 12.2 2.4 2.4 4.6-4.8'/%3E%3C/svg%3E");
}

/* A flash is the answer to what was just done, so it stands a little apart from the page. */
.flash {
	box-shadow: var(--shadow-sm);
}

/* --- The application shell --- */

/*
 * The navigation is a column down the left, fixed, with the areas of the clinic grouped
 * under a small heading each. Seventeen links in one row was a bar that wrapped onto
 * three lines on a laptop; in a column they are a list somebody can read.
 *
 * It folds to a strip of icons (html.nav-collapsed, set by nav-state.js before the page
 * is drawn and toggled by the button at its foot or the "[" key). --nav-w is the width
 * it has right now, and everything that sits beside it reads that one variable.
 *
 * The fragment is the <header> every page already pulls in, so no page had to change to
 * get it: the page's <main class="content"> follows it, and that sibling is what makes
 * room for the column.
 */
:root {
	--nav-w: var(--sidebar-width);
	--appbar-h: 3.75rem;
}

html.nav-collapsed {
	--nav-w: var(--sidebar-rail);
}

.sidebar {
	position: fixed;
	z-index: 40;
	top: 0;
	bottom: 0;
	left: 0;
	width: var(--nav-w);
	display: flex;
	flex-direction: column;
	background: var(--surface);
	border-right: 1px solid var(--line);
	padding: var(--space-3) var(--space-2) var(--space-3);
	overflow: hidden;
	transition: width .18s ease;
}

/*
 * The head and the foot never shrink. In a column of fixed height a flex item gives up
 * height when the list does not fit, and the head did: it shrank under its own logo and
 * the sidebar's overflow cut the top of the drawing off.
 */
.sidebar-head,
.sidebar-foot {
	flex: none;
}

.sidebar-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	min-height: 3rem;
	padding: 0 var(--space-2) var(--space-1);
}

.sidebar-brand {
	display: block;
	line-height: 0;
}

.sidebar-logo {
	width: 116px;
	height: auto;
}

.sidebar-mark {
	display: none;
	width: 40px;
	height: 40px;
}

/*
 * Only the list of sections scrolls, when a short screen cannot hold it all: the logo
 * stays at the top and whoever is logged in stays at the foot.
 */
.nav {
	display: flex;
	flex-direction: column;
	gap: 1px;
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
	scrollbar-width: thin;
	font-size: .9rem;
}

/* Rows keep their height; the list scrolls instead of squeezing them. */
.nav > * {
	flex: none;
}

.nav-group {
	margin: .7rem var(--space-3) 2px;
	font-size: .68rem;
	font-weight: 800;
	letter-spacing: .09em;
	text-transform: uppercase;
	color: var(--ink-muted);
	white-space: nowrap;
}

.nav a {
	position: relative;
	display: flex;
	align-items: center;
	gap: .65rem;
	height: 2rem;
	padding: 0 .7rem;
	border-radius: var(--radius-md);
	color: var(--ink);
	font-weight: 600;
	text-decoration: none;
	white-space: nowrap;
	transition: background-color .12s ease, color .12s ease;
}

.nav a .icon {
	width: 1.15rem;
	height: 1.15rem;
	color: var(--ink-muted);
}

.nav a:hover {
	background: var(--surface-sunken);
	color: var(--ink);
}

/*
 * Where you are, in the axolotl's pink: the one place the brand colour is spent on the
 * working screens. Bold as well as tinted, so it does not rest on colour alone.
 */
.nav a.is-active {
	background: var(--rose-100);
	color: var(--rose-700);
	font-weight: 800;
}

.nav a.is-active .icon {
	color: var(--rose-600);
}

.sidebar-foot {
	margin-top: auto;
	padding: var(--space-3) 0 0;
	border-top: 1px solid var(--line);
	display: flex;
	flex-direction: column;
	gap: var(--space-1);
}

.sidebar-account {
	position: relative;
	display: flex;
	align-items: center;
	gap: .6rem;
	min-width: 0;
	text-decoration: none;
	color: var(--ink);
	border-radius: var(--radius-md);
	padding: .3rem .35rem;
}

.sidebar-account:hover {
	background: var(--surface-sunken);
	color: var(--ink);
}

.avatar {
	flex: none;
	width: 2.1rem;
	height: 2.1rem;
	border-radius: 50%;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	background: var(--rose-200);
	color: var(--rose-700);
	font-weight: 800;
	font-size: .92rem;
	text-transform: uppercase;
}

.sidebar-account-text {
	display: flex;
	flex-direction: column;
	min-width: 0;
	line-height: 1.3;
}

.sidebar-account-name {
	font-weight: 700;
	font-size: .86rem;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.sidebar-account-role {
	font-size: .76rem;
	color: var(--ink-muted);
}

.sidebar-tools {
	display: flex;
	gap: 2px;
}

.sidebar-tools form {
	flex: 1;
	margin: 0;
}

.sidebar-tool {
	position: relative;
	display: flex;
	gap: .55rem;
	align-items: center;
	width: 100%;
	height: 2.15rem;
	padding: 0 .7rem;
	background: none;
	color: var(--ink-muted);
	font-weight: 700;
	font-size: .85rem;
	border-radius: var(--radius-md);
	white-space: nowrap;
}

.sidebar-tool:hover {
	background: var(--surface-sunken);
	color: var(--ink);
}

.sidebar-collapse {
	width: auto;
	flex: none;
}

/* A square button holding one icon: the menu, the search on a phone, closing things. */
.icon-button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.5rem;
	height: 2.5rem;
	padding: 0;
	background: none;
	color: var(--ink);
	border-radius: var(--radius-md);
}

.icon-button:hover {
	background: var(--surface-sunken);
}

.icon-button .icon {
	width: 1.35rem;
	height: 1.35rem;
}

.nav-close,
.nav-scrim {
	display: none;
}

/* --- The sidebar folded to its icons --- */

/*
 * The words leave sight but not the page: clipped rather than display:none, so a screen
 * reader still reads "Agenda" on a link that shows only a calendar. The word comes back
 * beside the icon as a label when the pointer rests on it, from the link's data-tip.
 */
html.nav-collapsed .sidebar {
	padding-left: var(--space-2);
	padding-right: var(--space-2);
}

html.nav-collapsed .sidebar-logo {
	display: none;
}

html.nav-collapsed .sidebar-mark {
	display: block;
}

/* The folded list still scrolls on a short screen, without a bar eating its 64 pixels. */
html.nav-collapsed .nav {
	scrollbar-width: none;
}

html.nav-collapsed .nav::-webkit-scrollbar {
	display: none;
}

html.nav-collapsed .sidebar-head {
	justify-content: center;
	padding: 0 0 var(--space-2);
}

html.nav-collapsed .nav-label {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

html.nav-collapsed .nav a,
html.nav-collapsed .sidebar-tool {
	justify-content: center;
	padding: 0;
}

html.nav-collapsed .nav-group {
	height: 1px;
	margin: var(--space-2) var(--space-2);
	background: var(--line);
	color: transparent;
	overflow: hidden;
}

html.nav-collapsed .sidebar-account {
	justify-content: center;
}

html.nav-collapsed .sidebar-tools {
	flex-direction: column;
}

html.nav-collapsed .sidebar-collapse .icon {
	transform: scaleX(-1);
}

/*
 * The label that appears beside a folded entry. Drawn by nav.js as one element fixed to
 * the window rather than as an ::after inside the link: the list scrolls when the window
 * is short, and a scrolling box clips whatever pokes out of it sideways.
 */
.nav-tip {
	position: fixed;
	z-index: 80;
	transform: translateY(-50%);
	padding: .3rem .6rem;
	border-radius: var(--radius-sm);
	background: var(--ink);
	color: #fff;
	font-size: .8rem;
	font-weight: 700;
	white-space: nowrap;
	pointer-events: none;
	box-shadow: var(--shadow-md);
}

/* --- The bar across the top --- */

/*
 * Sticky to the top of the window, beside the column. Paper with a blur rather than a
 * solid band, so it reads as the top of the page and not as a second header.
 */
.appbar {
	position: sticky;
	top: 0;
	z-index: 30;
	display: flex;
	align-items: center;
	gap: var(--space-4);
	height: var(--appbar-h);
	margin-left: var(--nav-w);
	padding: 0 2.5rem;
	background: rgba(250, 246, 241, .88);
	-webkit-backdrop-filter: blur(8px);
	backdrop-filter: blur(8px);
	border-bottom: 1px solid var(--line);
	transition: margin-left .18s ease;
}

/* Looks like a search box and is a button: it opens the search window. */
.appbar-search {
	display: flex;
	align-items: center;
	gap: .6rem;
	flex: 0 1 30rem;
	height: 2.4rem;
	padding: 0 .5rem 0 .85rem;
	background: var(--surface);
	color: var(--ink-muted);
	border: 1px solid var(--line-strong);
	border-radius: var(--radius-md);
	font-weight: 500;
	font-size: .92rem;
	text-align: left;
	cursor: text;
}

.appbar-search:hover {
	background: var(--surface);
	border-color: var(--tide-300);
}

.appbar-search-text {
	flex: 1;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.appbar-right {
	display: flex;
	align-items: center;
	gap: var(--space-4);
	margin-left: auto;
}

.appbar-date {
	display: inline-flex;
	align-items: center;
	gap: .4rem;
	color: var(--ink-muted);
	font-size: .88rem;
	font-weight: 600;
	white-space: nowrap;
}

.appbar-clock {
	padding-left: .5rem;
	margin-left: .1rem;
	border-left: 1px solid var(--line-strong);
	color: var(--ink);
	font-weight: 800;
	font-variant-numeric: tabular-nums;
}

.appbar-date span::first-letter {
	text-transform: uppercase;
}

.appbar .button {
	height: 2.4rem;
}

/* --- The search window --- */

.palette {
	position: fixed;
	inset: 0;
	z-index: 70;
	display: flex;
	justify-content: center;
	align-items: flex-start;
	padding: 12vh var(--space-4) var(--space-4);
}

.palette[hidden] {
	display: none;
}

.palette-scrim {
	position: absolute;
	inset: 0;
	background: rgba(42, 33, 36, .35);
	-webkit-backdrop-filter: blur(2px);
	backdrop-filter: blur(2px);
}

.palette-dialog {
	position: relative;
	width: min(40rem, 100%);
	max-height: 70vh;
	display: flex;
	flex-direction: column;
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-lg);
	overflow: hidden;
	animation: palette-in .14s ease-out;
}

@keyframes palette-in {
	from { opacity: 0; transform: translateY(-6px) scale(.98); }
}

.palette-input {
	display: flex;
	align-items: center;
	gap: .7rem;
	padding: 0 1rem;
	border-bottom: 1px solid var(--line);
	color: var(--ink-muted);
}

/* The box itself carries no frame: the window is the frame. Three :not() deep, as always. */
.palette-input input:not([type="checkbox"]):not([type="radio"]):not(.visually-hidden) {
	flex: 1;
	height: 3.4rem;
	padding: 0;
	border: none;
	background: none;
	font-size: 1.05rem;
}

.palette-input input:focus {
	outline: none;
}

/* The browser's own clear cross is a few pixels wide; ours replaces it. */
.palette-input input::-webkit-search-cancel-button {
	-webkit-appearance: none;
	display: none;
}

.palette-input .palette-clear {
	flex: none;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.5rem;
	height: 2.5rem;
	margin-right: -.5rem;
	padding: 0;
	border: none;
	border-radius: 50%;
	background: none;
	color: var(--ink-muted);
	cursor: pointer;
}

.palette-input .palette-clear:hover {
	background: var(--surface-sunken);
	color: var(--ink);
}

.palette-input .palette-clear[hidden] {
	display: none;
}

.palette-clear .icon {
	width: 1.15rem;
	height: 1.15rem;
}

/* A password box with the eye inside its right edge. */
.password-field {
	position: relative;
	display: block;
}

.password-field input:not([type="checkbox"]):not([type="radio"]):not(.visually-hidden) {
	width: 100%;
	padding-right: 3.25rem;
}

.password-field .password-toggle {
	position: absolute;
	top: 50%;
	right: .35rem;
	transform: translateY(-50%);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.5rem;
	height: 2.5rem;
	margin: 0;
	padding: 0;
	border: none;
	border-radius: 50%;
	background: none;
	color: var(--ink-muted);
	cursor: pointer;
}

.password-field .password-toggle:hover {
	background: var(--surface-sunken);
	color: var(--ink);
}

/* Edge draws its own eye in password boxes; one is enough. */
.password-field input::-ms-reveal {
	display: none;
}

.palette-results {
	overflow-y: auto;
	padding: .35rem;
}

.palette-group {
	margin: .55rem .65rem .25rem;
	font-size: .68rem;
	font-weight: 800;
	letter-spacing: .09em;
	text-transform: uppercase;
	color: var(--ink-muted);
}

.palette-item {
	display: flex;
	align-items: center;
	gap: .75rem;
	padding: .55rem .65rem;
	border-radius: var(--radius-md);
	color: var(--ink);
	text-decoration: none;
}

.palette-item .icon {
	color: var(--ink-muted);
}

.palette-item.is-active {
	background: var(--tide-50);
	color: var(--ink);
}

.palette-item.is-active .icon {
	color: var(--tide-700);
}

.palette-item-text {
	display: flex;
	flex-direction: column;
	min-width: 0;
	flex: 1;
	line-height: 1.3;
}

.palette-item-title {
	font-weight: 700;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.palette-item-detail {
	font-size: .82rem;
	color: var(--ink-muted);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.palette-note {
	margin: .75rem .65rem;
	font-size: .88rem;
	color: var(--ink-muted);
}

html.palette-open {
	overflow: hidden;
}

/* --- Confirmations in the corner --- */

/*
 * A green flash floats in the bottom corner and leaves by itself (nav.js). The red ones
 * stay where they are, in the page: an error is read in the place it happened.
 */
.alert-ok.flash {
	position: fixed;
	z-index: 60;
	right: 1.5rem;
	bottom: 1.5rem;
	max-width: 26rem;
	margin: 0;
	padding-right: 2.6rem;
	border-color: rgba(42, 107, 68, .18);
	box-shadow: var(--shadow-lg);
	animation: toast-in .22s ease-out;
}

.alert-ok.flash.is-leaving {
	opacity: 0;
	transform: translateY(8px);
	transition: opacity .25s ease, transform .25s ease;
}

@keyframes toast-in {
	from { opacity: 0; transform: translateY(12px); }
}

.toast-close {
	position: absolute;
	top: .35rem;
	right: .4rem;
	width: 1.8rem;
	height: 1.8rem;
	padding: 0;
	background: none;
	color: inherit;
	font-size: 1.2rem;
	line-height: 1;
	border-radius: var(--radius-sm);
}

.toast-close:hover {
	background: rgba(42, 107, 68, .1);
}

/* The bar a phone gets instead of the column: the logo, the search and the menu button. */
.mobilebar {
	display: none;
}

.mobilebar-actions {
	display: flex;
	gap: 2px;
}

/*
 * The page beside the column. Centred in the room the column leaves rather than in the
 * window, or on a wide screen the page sat under the column's right edge. 100vw counts
 * the scrollbar, which puts the centre a few pixels off; nobody can see four pixels.
 */
.app-nav ~ .content {
	margin-left: max(var(--nav-w), calc((100vw + var(--nav-w) - var(--content-max)) / 2));
	margin-right: auto;
	transition: margin-left .18s ease;
}

/*
 * Under a laptop's width the column leaves the screen and comes back over the page when
 * asked for, always at full width and with a veil behind it that closes it again. The
 * folded strip is a desktop thing; on a phone it would only take room from the page.
 */
@media (max-width: 960px) {
	:root,
	html.nav-collapsed {
		--nav-w: 0px;
	}

	.mobilebar {
		position: sticky;
		top: 0;
		z-index: 30;
		display: flex;
		align-items: center;
		justify-content: space-between;
		height: 3.5rem;
		padding: 0 var(--space-2) 0 var(--space-4);
		background: var(--surface);
		border-bottom: 1px solid var(--line);
	}

	.mobilebar img {
		display: block;
		width: 104px;
		height: auto;
	}

	.appbar {
		display: none;
	}

	.sidebar,
	html.nav-collapsed .sidebar {
		width: var(--sidebar-width);
		overflow: hidden;
		transform: translateX(-100%);
		transition: transform .2s ease;
	}

	html.nav-collapsed .sidebar-logo {
		display: block;
	}

	html.nav-collapsed .nav {
		overflow-y: auto;
	}

	html.nav-collapsed .sidebar-mark,
	.nav-tip {
		display: none;
	}

	html.nav-collapsed .nav-label {
		position: static;
		width: auto;
		height: auto;
		clip-path: none;
	}

	html.nav-collapsed .nav a,
	html.nav-collapsed .sidebar-tool {
		justify-content: flex-start;
		padding: 0 .7rem;
	}

	html.nav-collapsed .nav-group {
		height: auto;
		background: none;
		color: var(--ink-muted);
		margin: var(--space-3) var(--space-3) 2px;
	}

	.sidebar-collapse {
		display: none;
	}

	.app-nav.is-open .sidebar {
		transform: none;
		box-shadow: var(--shadow-lg);
	}

	.nav-close {
		display: inline-flex;
	}

	.app-nav.is-open .nav-scrim {
		display: block;
		position: fixed;
		inset: 0;
		z-index: 35;
		background: rgba(42, 33, 36, .35);
	}

	.app-nav ~ .content {
		margin-left: auto;
	}

	.alert-ok.flash {
		left: 1rem;
		right: 1rem;
		bottom: 1rem;
		max-width: none;
	}

	.palette {
		padding-top: 4rem;
	}
}

.badge {
	display: inline-flex;
	align-items: center;
	gap: .3rem;
	background: var(--surface-sunken);
	border: 1px solid var(--line);
	border-radius: var(--radius-pill);
	padding: .05rem .6rem;
	font-size: .75rem;
	font-weight: 700;
	color: var(--ink-muted);
	letter-spacing: .02em;
	white-space: nowrap;
	vertical-align: .1em;
	line-height: 1.6;
}

/* Beside a page's title the badge is read with it, so it grows with the heading. */
h1 .badge {
	font-size: .8rem;
	vertical-align: .3em;
}

.badge-ok {
	background: var(--ok-bg);
	color: var(--ok-ink);
	border-color: transparent;
}

/*
 * The one badge that means "be careful with your hands". Stronger than badge-warn, which
 * the diary already spends on allergies — two warnings that look identical are one
 * warning nobody ranks.
 */
.badge-danger {
	background: var(--danger-bg);
	color: var(--danger-ink);
	border-color: var(--danger-line);
	font-weight: 800;
}

.badge-warn {
	background: var(--warn-bg);
	color: var(--warn-ink);
	border-color: transparent;
}

.inline {
	display: inline;
}

/*
 * A table cell holding several actions. Flex rather than leaving them inline, because
 * each action that changes something is its own <form> — a POST needs one around it to
 * carry the CSRF token — and forms sitting next to each other inherit the whitespace
 * between the tags as their only separation.
 */
.row-actions {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: .25rem 1rem;
}

/*
 * Except on a table cell, which has to stay a cell. As a flex box it left the table's
 * layout: its bottom border sat a few pixels off the rest of the row, which the old
 * collapsed borders hid and the rounded table no longer does. Inline forms with a margin
 * between them give the same row of actions.
 */
td.row-actions {
	display: table-cell;
	white-space: nowrap;
}

td.row-actions > * + * {
	margin-left: 1rem;
}

td.row-actions form {
	display: inline;
}

/* A generated password being read out or copied down, so it has to be unambiguous. */
.temporary-password {
	font-size: 1.05rem;
	letter-spacing: .04em;
	background: var(--surface);
	padding: .1rem .4rem;
	border-radius: var(--radius-sm);
}

.link-button {
	width: auto;
	background: none;
	border: none;
	color: var(--tide-700);
	padding: 0;
	font-size: .9rem;
	font-weight: 700;
	cursor: pointer;
	text-decoration: underline;
	text-underline-offset: .15em;
}

.link-button:hover {
	background: none;
	color: var(--tide-800);
}

/* --- Content --- */

.content {
	max-width: var(--content-max);
	margin: 0 auto;
	padding: 2rem 2.5rem 4rem;
}

.content h1 {
	font-size: 1.75rem;
	font-weight: 800;
	margin-top: 0;
}

.content h2 {
	font-weight: 800;
}

@media (max-width: 640px) {
	.content {
		padding: 1.25rem 1rem 3rem;
	}

	.content h1 {
		font-size: 1.45rem;
	}
}

.page-header {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 1rem;
	flex-wrap: wrap;
	margin-bottom: 1.5rem;
}

.page-header h1, .page-header h2 {
	margin: 0;
}

.page-header p {
	margin: .2rem 0 0;
}

/*
 * The first screen of each area of the clinic: the title in a pink band with the axolotl
 * doing that area's job beside it. Only on the screen you land on — a list, a day — and
 * never on a form or a file, where the room belongs to the work.
 */
.page-hero {
	align-items: center;
	flex-wrap: nowrap;
	gap: var(--space-5);
	padding: var(--space-3) var(--space-6) var(--space-3) var(--space-3);
	background: var(--rose-50);
	border: 1px solid var(--rose-100);
	border-radius: var(--radius-lg);
	min-height: 7.5rem;
}

/* Over a form, as wide as the form beneath it rather than the page. */
.page-hero-narrow {
	max-width: 900px;
}

.hero-mascot {
	flex: none;
	width: auto;
	height: 6.5rem;
	margin: -.25rem 0;
}

.hero-text {
	flex: 1 1 auto;
	min-width: 0;
}

.hero-text .muted {
	max-width: 40rem;
}

.page-hero .header-actions {
	flex: none;
}

@media (max-width: 720px) {
	.page-hero {
		flex-wrap: wrap;
		padding: var(--space-3) var(--space-4);
	}

	.hero-mascot {
		height: 4.5rem;
	}

	.hero-text {
		flex-basis: calc(100% - 6rem);
	}

	.page-hero .header-actions {
		flex: 1 0 100%;
	}
}

/*
 * A header whose actions always get their own line.
 *
 * The ordinary .page-header shares one line between the title and the buttons and lets
 * them wrap when they do not fit. That is fine with one button and wrong with six: the
 * left-hand block is as wide as the animal's name, species and breed happen to be, so
 * whether the row wraps depends on the animal. Two files opened one after the other were
 * laid out differently — Miu's fitted and Eevee's did not — and it read as the page being
 * broken rather than as text being longer.
 *
 * Giving the actions their own row costs one line of height and makes every animal's file
 * look the same, which is what somebody moving between them all morning actually needs.
 */
.page-header-stacked .header-actions {
	flex: 1 0 100%;
}

.breadcrumb {
	margin: 0 0 .9rem;
	font-size: .9rem;
	font-weight: 600;
}

.breadcrumb a {
	text-decoration: none;
	color: var(--ink-muted);
}

.breadcrumb a:hover {
	color: var(--tide-700);
}

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

/*
 * Three different elements wear this class — <a>, <label> and <button> — and they have
 * to come out the same height to the pixel. Two things stopped that:
 *
 *   border: the primary variant had none and .button-secondary adds 1px, so the solid
 *   button was 1.33px shorter than the ones beside it. A transparent border keeps the
 *   box identical and lets the variant only change its colour.
 *
 *   line-height: a <button> gets `normal` from the browser instead of inheriting, so
 *   it came out 2px shorter than an <a> with the same padding and font. Stating it
 *   here makes the three agree.
 *
 *   margin: `label` carries margin-bottom: .35rem for form fields, which a <label>
 *   styled as a button inherited — 5.6px that sat it 2.8px above everything else and
 *   made the whole row taller than any button in it.
 */
.button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: .45rem;
	margin: 0;
	padding: .55rem 1.05rem;
	background: var(--tide-700);
	color: #fff;
	border: 1px solid transparent;
	border-radius: var(--radius-md);
	text-decoration: none;
	font-size: .92rem;
	line-height: 1.5;
	font-weight: 700;
	white-space: nowrap;
	cursor: pointer;
	transition: background-color .12s ease, border-color .12s ease, color .12s ease;
}

.button:hover {
	background: var(--tide-800);
	color: #fff;
}

.button .icon {
	width: 1.1rem;
	height: 1.1rem;
	margin-left: -.15rem;
}

.button-secondary {
	background: var(--surface);
	color: var(--tide-700);
	/* Only the colour: the 1px is already in .button so the box does not change. */
	border-color: var(--line-strong);
}

.button-secondary:hover {
	background: var(--tide-50);
	color: var(--tide-800);
	border-color: var(--tide-300);
}

.button-danger {
	background: var(--danger-ink);
}

.button-danger:hover {
	background: var(--danger-strong);
}

/* Destructive but not the point of the screen: white, with the words in the danger colour. */
.button-danger-outline,
.button-danger-outline:hover {
	color: var(--danger-ink);
}

.button-danger-outline:hover {
	background: var(--danger-bg);
	border-color: var(--danger-line);
}

/* --- Tabs --- */

/* Two or three views of the same thing, side by side over it: accounts and debtors. */
.tabs {
	display: flex;
	gap: .25rem;
	margin: 0 0 1.25rem;
	border-bottom: 1px solid var(--line);
}

.tabs a {
	display: inline-flex;
	align-items: center;
	gap: .45rem;
	padding: .55rem .9rem;
	margin-bottom: -1px;
	border-bottom: 2px solid transparent;
	color: var(--ink-muted);
	font-weight: 700;
	text-decoration: none;
}

.tabs a:hover {
	color: var(--ink);
}

.tabs a.is-active {
	color: var(--ink);
	border-bottom-color: var(--tide-700);
}

.tab-count {
	min-width: 1.4rem;
	padding: 0 .4rem;
	border-radius: var(--radius-pill);
	background: var(--warn-bg);
	color: var(--warn-ink);
	font-size: .75rem;
	font-weight: 800;
	text-align: center;
}

/* A second line under a name in a table cell. */
.cell-note {
	margin-top: .15rem;
	padding-left: 2.45rem;
	font-size: .82rem;
}

/* A second line in a cell that has no avatar to line up with. */
.cell-note-plain {
	margin-top: .1rem;
	font-size: .82rem;
}

.sales-totals {
	margin: 0 0 .9rem;
}

/* The debt at the head of a customer's file: the amount, and the account to open. */
.debt-alert {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	justify-content: space-between;
	gap: .5rem 1rem;
}

.debt-alert a {
	color: var(--warn-ink);
	font-weight: 800;
}

/* Under the customer among the animal's facts, in the warning colour. */
.fact-debt {
	align-self: flex-start;
	margin-top: .3rem;
	padding: .05rem .55rem;
	border-radius: var(--radius-pill);
	background: var(--warn-bg);
	color: var(--warn-ink);
	font-size: .78rem;
	font-weight: 800;
	text-decoration: none;
}

.fact-debt:hover {
	color: var(--warn-ink);
	text-decoration: underline;
}

/* The size of a list before it, when the list is the whole of something. */
.list-count {
	margin: 0 0 .75rem;
	font-size: .9rem;
}

/* --- Filters and ordering --- */

/*
 * The search box and the filters are one GET form, so nothing typed is lost when a
 * filter is applied. The filters fold into a panel; it opens by itself while any is on.
 */
.search-filters-form {
	margin-bottom: 1.25rem;
}

.search-filters-form .search {
	margin-bottom: .75rem;
}

.filter-panel {
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-sm);
}

.filter-panel > summary {
	display: flex;
	align-items: center;
	gap: .5rem;
	margin: 0;
	padding: .7rem 1rem;
	color: var(--ink);
	font-weight: 800;
	list-style: none;
	cursor: pointer;
}

.filter-panel > summary::-webkit-details-marker {
	display: none;
}

.filter-panel > summary::after {
	content: "";
	width: .5rem;
	height: .5rem;
	margin-left: auto;
	border-right: 2px solid var(--ink-muted);
	border-bottom: 2px solid var(--ink-muted);
	transform: rotate(45deg) translateY(-2px);
	transition: transform .15s ease;
}

.filter-panel[open] > summary::after {
	transform: rotate(-135deg) translateY(-2px);
}

.filter-panel > summary .icon {
	color: var(--ink-muted);
}

.filter-panel[open] > summary {
	border-bottom: 1px solid var(--line);
}

.filter-count {
	min-width: 1.4rem;
	padding: 0 .45rem;
	border-radius: var(--radius-pill);
	background: var(--tide-700);
	color: #fff;
	font-size: .75rem;
	font-weight: 800;
	text-align: center;
}

.filter-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(11.5rem, 1fr));
	gap: .25rem 1rem;
	padding: 1rem 1rem 0;
}

.filter-grid .field {
	margin-bottom: .75rem;
}

/* A pair of boxes in one cell: from and to, minimum and maximum. */
.filter-range {
	display: flex;
	gap: .4rem;
}

/*
 * Each box of the pair may shrink to its half. A flex item will not go below its own
 * content's width unless told to, and a date box's is wide: the second one ran out of
 * its cell and over the field next to it.
 */
.filter-range > input {
	flex: 1 1 0;
	min-width: 0;
}

/* A pair of dates needs the room of two fields to show both whole. */
.filter-grid .field-span-2 {
	grid-column: span 2;
}

@media (max-width: 560px) {
	.filter-grid .field-span-2 {
		grid-column: auto;
	}

	.filter-range {
		flex-direction: column;
	}
}

.filter-actions {
	display: flex;
	align-items: center;
	gap: 1rem;
	padding: .25rem 1rem 1rem;
}

/*
 * A heading that orders its column: the whole heading is the link, the arrow beside the
 * one that orders the list now. Same small capitals as any heading, darker when chosen.
 */
.table th.sortable {
	padding: 0;
}

.table th.sortable a {
	display: flex;
	align-items: center;
	gap: .3rem;
	padding: .7rem .9rem;
	color: inherit;
	font-weight: inherit;
	text-decoration: none;
}

.table th.sortable.numeric a {
	justify-content: flex-end;
}

.table th.sortable a:hover {
	color: var(--ink);
	background: var(--line);
	text-decoration: none;
}

.table th.sortable a.is-sorted {
	color: var(--tide-700);
}

.sort-arrow {
	font-size: .85rem;
	line-height: 1;
}

/* --- Search --- */

.search {
	display: flex;
	align-items: center;
	gap: .6rem;
	margin-bottom: 1.25rem;
}

.search input {
	max-width: 440px;
}

/* --- Tables --- */

/*
 * Every table sits in one of these, and it is the only thing standing between a narrow
 * screen and a page that slides sideways.
 *
 * The agenda's table is 775px of columns. On a phone that does not clip and it does not
 * wrap — it widens the document, so the whole page moves under the thumb and the menu and
 * the headings go with it. Exactly the bug the top bar had until its links were allowed
 * to wrap; this is the same fault in the other direction, and it is on nine screens.
 *
 * A wrapper rather than making the table itself the scrolling box: a table set to
 * display:block stops stretching to the width of its container, so every narrow table —
 * the staff list, the protocols — would bunch its columns to the left of an empty box.
 * The wrapper scrolls and the table inside goes on behaving like a table.
 */
.table-scroll {
	overflow-x: auto;
	border-radius: var(--radius-lg);
}

/* The buttons that act on the ticked rows sit apart from the table, not stuck to its last row. */
.table-scroll + .inline-form {
	margin-top: 1.25rem;
}

/* A cell that reads as one piece: "12 años" never split over two lines. */
.nowrap {
	white-space: nowrap;
}

/*
 * The message as it will arrive, quoted rather than paraphrased. pre-wrap because the
 * line breaks the vet typed are part of the wording — collapsing them would show a
 * message that is not the one being sent.
 */
.message-preview {
	white-space: pre-wrap;
	background: var(--surface-sunken);
	border-radius: var(--radius-md);
	border-top-left-radius: var(--radius-sm);
	padding: .85rem 1.1rem;
	margin: .5rem 0 1rem;
}

/*
 * How the animal behaves, on its own file. Red through to green, and the word is always
 * beside the colour: this is a safety note and somebody who cannot tell red from green
 * still has to be able to read it.
 */
.behaviour-note {
	display: inline-flex;
	align-items: center;
	gap: .5rem;
	padding: .45rem .9rem;
	border-radius: var(--radius-pill);
	margin: 0 0 1rem;
	font-size: .9rem;
}

.behaviour-note::before {
	content: "";
	flex: none;
	width: .6rem;
	height: .6rem;
	border-radius: 50%;
	background: currentColor;
}

.behaviour-very_bad { background: var(--behaviour-very-bad-bg); color: var(--behaviour-very-bad-ink); }
.behaviour-bad      { background: var(--behaviour-bad-bg); color: var(--behaviour-bad-ink); }
.behaviour-normal   { background: var(--surface-sunken); color: var(--ink-muted); }
.behaviour-good     { background: var(--behaviour-good-bg); color: var(--behaviour-good-ink); }
.behaviour-very_good { background: var(--behaviour-very-good-bg); color: var(--behaviour-very-good-ink); }

/* A button that has to sit inside a table row without making the row taller. */
.button-small {
	padding: .2rem .65rem;
	font-size: .8rem;
	border-radius: var(--radius-sm);
}

/*
 * A whole message in a table cell. Clamped to three lines rather than left to run: the
 * list is for finding the wording you want, and the one you want is recognisable from
 * its first line. The full text is on the edit screen.
 */
.template-body {
	display: -webkit-box;
	-webkit-line-clamp: 3;
	-webkit-box-orient: vertical;
	overflow: hidden;
	max-width: 30rem;
	white-space: pre-wrap;
	color: var(--ink-muted);
	font-size: .85rem;
}

/*
 * separate and not collapse, because a collapsed table ignores its own border-radius and
 * the corners came out square inside a rounded frame.
 */
.table {
	width: 100%;
	border-collapse: separate;
	border-spacing: 0;
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--radius-lg);
	overflow: hidden;
	font-size: .93rem;
	box-shadow: var(--shadow-sm);
}

.table th, .table td {
	text-align: left;
	padding: .7rem .9rem;
	border-bottom: 1px solid var(--line);
	vertical-align: middle;
}

.table th {
	background: var(--surface-sunken);
	font-size: .72rem;
	font-weight: 800;
	text-transform: uppercase;
	letter-spacing: .07em;
	color: var(--ink-muted);
	white-space: nowrap;
}

.table tbody tr:last-child td {
	border-bottom: none;
}

.table tbody tr:hover {
	background: var(--surface-hover);
}

.table td a {
	font-weight: 700;
	text-decoration: none;
}

.table td a:hover {
	text-decoration: underline;
}

/*
 * A name in a list with its initial in a circle before it: rose for people, the tail's
 * blue for animals, so a column of names reads at a glance as one or the other.
 */
.name-cell {
	display: inline-flex;
	align-items: center;
	gap: .6rem;
	vertical-align: middle;
}

.table td a.name-cell:hover {
	text-decoration: none;
}

.table td a.name-cell:hover > span:last-child {
	text-decoration: underline;
}

.mini-avatar {
	flex: none;
	width: 1.85rem;
	height: 1.85rem;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border-radius: 50%;
	background: var(--rose-100);
	color: var(--rose-700);
	font-size: .8rem;
	font-weight: 800;
	text-transform: uppercase;
}

.mini-avatar-animal {
	background: var(--tide-100);
	color: var(--tide-700);
}

/* No photo: a small paw in the circle, the same mark the animal's file uses. */
.avatar-paw .icon {
	width: 55%;
	height: 55%;
}

/* The animal's own photo in the same circle the paw would fill. */
.avatar-photo {
	object-fit: cover;
	background: var(--surface-sunken);
}

.row-inactive .avatar-photo {
	filter: grayscale(1);
	opacity: .7;
}

.row-inactive .mini-avatar {
	background: var(--surface-sunken);
	color: var(--ink-muted);
}

.row-inactive td {
	color: var(--ink-muted);
	font-style: italic;
}

/*
 * The strip of pages under a long list: the numbers on one line, the "go to" box and
 * the rows-per-page choice on the next, both wrapping on a phone.
 */
.pagination {
	display: flex;
	flex-direction: column;
	gap: .7rem;
	margin-top: 1.25rem;
	font-size: .9rem;
}

.pagination-pages {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: .3rem;
}

.pagination-pages a,
.pagination-current,
.pagination-gap {
	min-width: 2rem;
	height: 2rem;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 0 .5rem;
	border-radius: var(--radius-md);
	text-decoration: none;
	font-weight: 700;
}

.pagination-pages a:hover {
	background: var(--tide-50);
}

.pagination-current {
	background: var(--tide-700);
	color: #fff;
}

.pagination-gap {
	color: var(--ink-muted);
}

.pagination-tools {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: .5rem 1.5rem;
	color: var(--ink);
}

.pagination-jump {
	display: flex;
	align-items: center;
	gap: .5rem;
}

.pagination-jump label {
	margin: 0;
	font-weight: 600;
	white-space: nowrap;
}

/* Four digits at most, and the global width:100% is written three classes deep. */
.pagination-tools .pagination-jump input[type="number"] {
	width: 5rem;
	height: 2.2rem;
	padding: .3rem .5rem;
}

/* The same height as the box beside it, or the pair looks like two sizes. */
.pagination-jump button {
	height: 2.2rem;
	padding: 0 .8rem;
}

.pagination-sizes {
	display: flex;
	align-items: center;
	gap: .5rem;
}

/* --- Detail blocks --- */

.card-block {
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--radius-lg);
	padding: 1.35rem 1.6rem;
	margin-bottom: 1.25rem;
	box-shadow: var(--shadow-sm);
}

.card-block h2 {
	font-size: 1.12rem;
	font-weight: 800;
	margin-top: 0;
}

.card-block h3 {
	font-size: .95rem;
	font-weight: 800;
	margin-bottom: .25rem;
}

.details {
	display: grid;
	grid-template-columns: max-content 1fr;
	gap: .5rem 1.5rem;
	margin: 0;
	font-size: .93rem;
}

.details dt {
	color: var(--ink-muted);
	font-weight: 700;
}

.details dd {
	margin: 0;
}

.notes {
	margin-top: 1rem;
	padding-top: 1rem;
	border-top: 1px solid var(--line);
}

/* --- Key facts on the patient file --- */

.key-facts {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
	gap: 1rem;
	margin-bottom: 1.25rem;
}

.fact {
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--radius-lg);
	padding: 1rem 1.15rem;
	display: flex;
	flex-direction: column;
	gap: .15rem;
	box-shadow: var(--shadow-sm);
}

.fact-label {
	font-size: .72rem;
	text-transform: uppercase;
	letter-spacing: .08em;
	color: var(--ink-muted);
	font-weight: 800;
}

.fact-value {
	font-size: 1.4rem;
	font-weight: 800;
	font-variant-numeric: tabular-nums;
}

.fact-value-small {
	font-size: .95rem;
	font-weight: 700;
	word-break: break-all;
}

/* The customer's name and phone among the facts: links, read like the other values. */
.fact-link {
	color: var(--tide-700);
	text-decoration: none;
	overflow-wrap: anywhere;
	word-break: normal;
}

.fact-link:hover {
	text-decoration: underline;
}

a.fact-note {
	color: var(--ink-muted);
}

.fact-note {
	font-size: .8rem;
	color: var(--ink-muted);
}

/* --- Home --- */

/*
 * The greeting: the axolotl waving, the date, the person's name and the day in one
 * sentence, with the two most common errands beside it. The same pink as the login, so
 * arriving here feels like the next step of coming in.
 */
.welcome {
	display: flex;
	align-items: center;
	gap: var(--space-5);
	padding: var(--space-3) var(--space-6) var(--space-3) var(--space-4);
	background: var(--rose-50);
	border: 1px solid var(--rose-100);
	border-radius: var(--radius-lg);
	margin-bottom: var(--space-5);
}

.welcome-mascot {
	flex: none;
	width: auto;
	height: 7.5rem;
	margin: -.5rem 0;
}

.welcome-text {
	flex: 1 1 auto;
	min-width: 0;
}

.welcome h1 {
	font-size: 1.9rem;
	margin: 0;
}

.welcome p {
	margin: .2rem 0 0;
	font-size: 1rem;
}

.welcome-actions {
	display: flex;
	gap: .5rem;
	flex: none;
}

@media (max-width: 720px) {
	.welcome {
		flex-wrap: wrap;
		gap: var(--space-3);
		padding: var(--space-3) var(--space-4);
	}

	.welcome-mascot {
		height: 5rem;
	}

	.welcome-text {
		flex-basis: calc(100% - 6rem);
	}

	.welcome h1 {
		font-size: 1.4rem;
	}

	.welcome-actions {
		flex: 1 0 100%;
		flex-wrap: wrap;
	}
}

/*
 * The day in four figures. Each card is a link to the screen behind its number, which is
 * how a figure on a dashboard earns its place: one look, and one click to the detail.
 */
.stats {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
	gap: var(--space-4);
	margin-bottom: var(--space-5);
}

.stat {
	display: flex;
	flex-direction: column;
	gap: .2rem;
	padding: 1rem 1.15rem 1.05rem;
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-sm);
	color: var(--ink);
	text-decoration: none;
	transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}

.stat:hover {
	border-color: var(--tide-300);
	box-shadow: var(--shadow-md);
	transform: translateY(-1px);
	color: var(--ink);
}

.stat-label {
	display: flex;
	align-items: center;
	gap: .45rem;
	font-size: .72rem;
	font-weight: 800;
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--ink-muted);
}

.stat-label .icon {
	width: 1rem;
	height: 1rem;
}

.stat-value {
	font-size: 1.85rem;
	font-weight: 800;
	line-height: 1.15;
	letter-spacing: -.01em;
	font-variant-numeric: tabular-nums;
}

.stat-sub {
	font-size: .84rem;
	color: var(--ink-muted);
}

/* Money owed or a consent waiting: the figure wears the warning colour, with its words. */
.stat-warn .stat-value {
	color: var(--warn-ink);
}

.stat-bar {
	display: flex;
	height: .4rem;
	margin: .35rem 0 .15rem;
	border-radius: var(--radius-pill);
	background: var(--surface-sunken);
	overflow: hidden;
}

.stat-bar-done {
	background: var(--ok-ink);
}

.stat-bar-now {
	background: var(--warn-ink);
}

/* The diary on the left, the things waiting on somebody on the right. */
.dashboard {
	display: grid;
	grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
	gap: var(--space-4);
	align-items: start;
}

.dashboard .card-block {
	margin-bottom: 0;
}

.dashboard-side {
	display: flex;
	flex-direction: column;
	gap: var(--space-4);
}

@media (max-width: 1100px) {
	.dashboard {
		grid-template-columns: 1fr;
	}
}

/* A card's heading with a link to the full screen at its right. */
.card-head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1rem;
	margin-bottom: .75rem;
}

.card-head h2 {
	margin: 0;
}

.card-link {
	display: inline-flex;
	align-items: center;
	gap: .3rem;
	font-size: .86rem;
	font-weight: 700;
	text-decoration: none;
	white-space: nowrap;
}

.card-foot {
	margin: .75rem 0 0;
	font-size: .88rem;
}

/*
 * Today's visits as a list rather than a table: the hour, the animal's initial, who it is
 * and what for, and the warnings at the end of the line where the eye finishes.
 */
.visit-list {
	list-style: none;
	margin: 0 -.5rem;
	padding: 0;
}

.visit-list li {
	display: flex;
	align-items: center;
	gap: .85rem;
	padding: .6rem .5rem;
	border-radius: var(--radius-md);
	border-top: 1px solid var(--line);
}

.visit-list li:first-child {
	border-top: none;
}

.visit-list li:hover {
	background: var(--surface-hover);
}

/* The one in the room, held out from the rest. */
.visit-list li.is-now {
	background: var(--warn-bg);
	border-top-color: transparent;
}

.visit-list li.is-now + li {
	border-top-color: transparent;
}

/* On the amber row the amber badge would vanish, so it sits on white there. */
.visit-list li.is-now .badge-warn {
	background: var(--surface);
}

.visit-time {
	flex: none;
	width: 3.2rem;
	font-weight: 800;
	font-variant-numeric: tabular-nums;
}

.visit-avatar {
	flex: none;
	width: 2.25rem;
	height: 2.25rem;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border-radius: 50%;
	background: var(--tide-100);
	color: var(--tide-700);
	font-weight: 800;
	text-transform: uppercase;
}

.visit-main {
	display: flex;
	flex-direction: column;
	min-width: 0;
	flex: 1;
	line-height: 1.35;
}

.visit-name {
	font-weight: 800;
	text-decoration: none;
	color: var(--ink);
}

.visit-name:hover {
	color: var(--tide-700);
	text-decoration: underline;
}

.visit-detail {
	font-size: .85rem;
	color: var(--ink-muted);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.visit-flags {
	display: flex;
	flex-wrap: wrap;
	justify-content: flex-end;
	gap: .3rem;
}

@media (max-width: 560px) {
	.visit-avatar {
		display: none;
	}

	.visit-list li {
		flex-wrap: wrap;
	}

	.visit-flags {
		flex: 1 0 100%;
		justify-content: flex-start;
		padding-left: 4rem;
	}
}

/* A short list in a side card: a name on the left, its state on the right. */
.side-list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.side-list li {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: .75rem;
	padding: .5rem 0;
	border-top: 1px solid var(--line);
	font-size: .92rem;
}

.side-list li:first-child {
	border-top: none;
	padding-top: 0;
}

.side-list a {
	font-weight: 700;
	text-decoration: none;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.side-list a:hover {
	text-decoration: underline;
}

/* Nothing to do here, said plainly and in green. */
.all-clear {
	display: flex;
	align-items: center;
	gap: .5rem;
	margin: 0;
	color: var(--ok-ink);
	font-size: .92rem;
	font-weight: 600;
}

.section-title {
	margin: 0 0 var(--space-3);
	font-size: .75rem;
	font-weight: 800;
	letter-spacing: .09em;
	text-transform: uppercase;
	color: var(--ink-muted);
}

.shortcuts {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
	gap: 1rem;
	margin: 0 0 2rem;
}

.shortcut {
	position: relative;
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--radius-lg);
	padding: 1.15rem 1.25rem;
	text-decoration: none;
	color: inherit;
	display: flex;
	flex-direction: column;
	gap: .3rem;
	box-shadow: var(--shadow-sm);
	transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}

.shortcut:hover {
	border-color: var(--tide-300);
	box-shadow: var(--shadow-md);
	transform: translateY(-1px);
	color: inherit;
}

.shortcut-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.6rem;
	height: 2.6rem;
	margin-bottom: .35rem;
	border-radius: var(--radius-md);
	background: var(--rose-100);
	color: var(--rose-700);
}

.shortcut-icon .icon {
	width: 1.4rem;
	height: 1.4rem;
}

.shortcut-title {
	font-weight: 800;
	color: var(--ink);
	font-size: 1.05rem;
}

.shortcut-text {
	font-size: .88rem;
	color: var(--ink-muted);
}

/* --- Empty and feedback states --- */

/*
 * What a screen shows when there is nothing on it: the axolotl, one sentence saying why,
 * and — when there is one — the button that fills it. A blank table with a grey line under
 * it reads as broken; this reads as "nothing yet".
 */
.empty-state {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	gap: .35rem;
	padding: var(--space-8) var(--space-6);
	background: var(--surface);
	border: 1px dashed var(--line-strong);
	border-radius: var(--radius-lg);
	margin: 0 0 1.25rem;
}

.empty-state img {
	width: auto;
	height: 8.5rem;
	margin-bottom: .5rem;
}

.empty-state-title {
	margin: 0;
	font-size: 1.08rem;
	font-weight: 800;
	color: var(--ink);
}

.empty-state p {
	margin: 0;
	max-width: 30rem;
	color: var(--ink-muted);
}

.empty-state .button {
	margin-top: .75rem;
}

/* The same inside a card, where the card already draws the frame. */
.empty-state-inline {
	border: none;
	padding: var(--space-4) var(--space-4) var(--space-2);
	margin: 0;
}

.empty-state-inline img {
	height: 6.5rem;
}

/* The same idea for a whole page that has nothing to offer: no permission, for one. */
.notice-page {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	padding: var(--space-10) var(--space-4);
}

.notice-page img {
	width: auto;
	height: 13rem;
	margin-bottom: var(--space-4);
}

.notice-page h1 {
	margin-bottom: .25rem;
}

.notice-page p {
	margin: 0 0 1.25rem;
	color: var(--ink-muted);
}

/* --- Menus and folded sections --- */

/*
 * A row of secondary actions folded behind "Más". The panel hangs below the button and
 * over the page; the forms inside are ordinary forms, laid out as a list.
 */
.menu {
	position: relative;
}

.menu > summary {
	list-style: none;
}

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

.menu[open] > summary {
	background: var(--tide-50);
	border-color: var(--tide-300);
}

/* A primary button keeps its fill while its menu is open, one shade darker. */
.menu[open] > summary.button:not(.button-secondary) {
	background: var(--tide-800);
	border-color: transparent;
}

.menu-panel {
	position: absolute;
	z-index: 25;
	top: calc(100% + .35rem);
	right: 0;
	min-width: 14rem;
	display: flex;
	flex-direction: column;
	padding: .35rem;
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--radius-md);
	box-shadow: var(--shadow-lg);
}

/*
 * A button that sits near the left edge, as "Más" does on a phone when it wraps to a
 * line of its own, hangs its panel to the right instead of off the screen (nav.js).
 */
.menu-panel-start {
	right: auto;
	left: 0;
}

.menu-panel form {
	margin: 0;
}

.menu-item {
	display: flex;
	align-items: center;
	gap: .6rem;
	width: 100%;
	margin: 0;
	padding: .5rem .7rem;
	background: none;
	border: none;
	border-radius: var(--radius-sm);
	color: var(--ink);
	font-size: .92rem;
	font-weight: 600;
	/* A button does not inherit it, and came out 3px shorter than the links beside it. */
	line-height: inherit;
	text-align: left;
	text-decoration: none;
	cursor: pointer;
}

.menu-item .icon {
	color: var(--ink-muted);
}

.menu-item:hover {
	background: var(--surface-sunken);
	color: var(--ink);
}

.menu-item-danger,
.menu-item-danger .icon,
.menu-item-danger:hover {
	color: var(--danger-ink);
}

/* Anything else folded into a <details>: the summary reads as a link to open it. */
details:not(.menu) > summary {
	cursor: pointer;
	color: var(--tide-700);
	font-weight: 700;
	margin: .75rem 0;
}

details:not(.menu)[open] > summary {
	margin-bottom: 1rem;
}

/* A tick box and its words beside a search box, as one piece. */
label.check {
	display: inline-flex;
	align-items: center;
	gap: .5rem;
	margin: 0;
	font-weight: 600;
	white-space: nowrap;
}

/*
 * The strip across the top of a long file that jumps to each part of it. Sticky, so it is
 * there from the middle of the page; on a phone it sits under the menu bar, and scrolls
 * sideways rather than wrapping into a block of links.
 */
.section-nav {
	position: sticky;
	top: calc(var(--appbar-h) + .5rem);
	z-index: 15;
	display: flex;
	gap: .25rem;
	overflow-x: auto;
	margin: 0 0 1.25rem;
	padding: .4rem;
	background: rgba(250, 246, 241, .92);
	-webkit-backdrop-filter: blur(6px);
	backdrop-filter: blur(6px);
	border: 1px solid var(--line);
	border-radius: var(--radius-lg);
	scrollbar-width: none;
}

.section-nav a {
	flex: none;
	padding: .35rem .8rem;
	border-radius: var(--radius-md);
	color: var(--ink-muted);
	font-size: .88rem;
	font-weight: 700;
	text-decoration: none;
	white-space: nowrap;
}

.section-nav a:hover {
	background: var(--surface);
	color: var(--ink);
}

/* Where a jump lands: clear of the sticky strip instead of underneath it. */
.card-block[id] {
	scroll-margin-top: 9rem;
}

@media (max-width: 960px) {
	.section-nav {
		top: 3.5rem;
	}

	.card-block[id] {
		scroll-margin-top: 8rem;
	}
}

/* --- Chips --- */

/* A count and what it counts, in a row under a title: the day at a glance. */
.chips {
	display: flex;
	flex-wrap: wrap;
	gap: .4rem;
	margin: .55rem 0 0;
}

.chip {
	display: inline-flex;
	align-items: baseline;
	gap: .3rem;
	padding: .15rem .65rem;
	border-radius: var(--radius-pill);
	background: var(--surface);
	border: 1px solid var(--rose-100);
	color: var(--ink-muted);
	font-size: .82rem;
	font-weight: 600;
	white-space: nowrap;
}

.chip strong {
	color: var(--ink);
	font-weight: 800;
	font-variant-numeric: tabular-nums;
}

.chip-ok {
	background: var(--ok-bg);
	border-color: transparent;
	color: var(--ok-ink);
}

.chip-ok strong {
	color: var(--ok-ink);
}

.chip-warn {
	background: var(--warn-bg);
	border-color: transparent;
	color: var(--warn-ink);
}

.chip-warn strong {
	color: var(--warn-ink);
}

/* --- Agenda --- */

.day-nav {
	display: flex;
	align-items: center;
	gap: .5rem;
	flex-wrap: wrap;
	margin-bottom: 1.25rem;
}

.day-jump {
	margin-bottom: 0;
	margin-left: auto;
}

/*
 * The date box is one control beside a button, not a field filling a form. Three
 * selectors deep on purpose: the global width:100% on inputs is written with three
 * :not() clauses, which count as classes, so a plain ".day-jump input" lost to it and
 * the box stretched across the row with "Ir" pushed underneath.
 */
.day-nav .day-jump input[type="date"] {
	width: auto;
}

.header-actions {
	display: flex;
	/* Without this the default is stretch, and the links grow to the height of the
	   tallest item while a button nested inside a form does not — which is what made
	   the row of actions look like five different sizes. */
	align-items: center;
	gap: .5rem;
	flex-wrap: wrap;
}

/*
 * A form in the header is one item of the row, holding one button.
 *
 * display:contents was tried first and flattens the form away, which sounds tidier and
 * is not: its children — including the hidden file input — all become flex items, and
 * the row started sizing itself to things nobody can see. An ordinary flex item with
 * no margin behaves like the links next to it and needs no explaining.
 */
.header-form {
	display: flex;
	align-items: center;
	margin: 0;
}

/*
 * The photo and the title are one item, not two. .page-header is space-between, so a
 * third child pushed the animal's name into the middle of the screen.
 */
.page-title {
	display: flex;
	align-items: center;
	gap: 1rem;
}

.agenda-time {
	white-space: nowrap;
	font-variant-numeric: tabular-nums;
}

.agenda-time strong {
	font-size: 1.05rem;
}

.agenda-actions {
	white-space: nowrap;
	text-align: right;
}

.agenda-actions form + form::before {
	content: " · ";
	color: var(--line-strong);
}

.link-danger {
	color: var(--danger-ink);
}

.link-danger:hover {
	color: var(--danger-strong);
}

/* --- The timetable --- */

/*
 * A shift, drawn as a box of a known height with everything inside it positioned by
 * percentage. The height comes from how many half hours it holds, so a five-hour morning
 * is taller than a three-hour afternoon and the two are drawn to the same scale — which
 * is the whole point of a timetable over a list.
 *
 * --slot-count is written by the template. 2.2rem a slot is enough for a name at a
 * legible size without a normal day needing to be scrolled.
 */
.slot-block {
	position: relative;
	height: calc(var(--slot-count) * 2.2rem);
	border: 1px solid var(--line);
	border-radius: var(--radius-lg);
	background: var(--surface);
	overflow: hidden;
	box-shadow: var(--shadow-sm);
}

/*
 * A free half hour: a link that books into it. Absolute, because its position is a
 * percentage of the shift rather than a place in a stack — that is what lets an
 * appointment starting at 10:07 sit exactly where it belongs instead of snapping to a row.
 */
.slot {
	position: absolute;
	left: 0;
	right: 0;
	display: flex;
	align-items: center;
	padding-left: .6rem;
	border-top: 1px solid var(--line);
	color: var(--ink-muted);
	text-decoration: none;
	font-size: .75rem;
	font-variant-numeric: tabular-nums;
}

.slot:first-child {
	border-top: none;
}

.slot:hover {
	background: var(--tide-50);
	color: var(--tide-700);
}

/* Only the hour marks carry a label; the half hours are lines, to keep the noise down. */
.slot-time {
	opacity: .7;
}

/*
 * An appointment, on top of the free slots it covers. Inset on the left so the hour
 * marks underneath stay readable down the edge of the block.
 */
/*
 * Placed by percentages from the top, and — when two vets have the same hour — split
 * across the row into lanes. --lane and --lanes come from DaySchedule on each block; on
 * its own a block is lane 0 of 1 and the arithmetic below comes out as the full width,
 * exactly as it was drawn before there were lanes.
 */
.slot-entry {
	position: absolute;
	--gutter-left: 3.4rem;
	--gutter-right: .35rem;
	--lane-gap: .25rem;
	--lane-width: calc((100% - var(--gutter-left) - var(--gutter-right)
	                    - var(--lane-gap) * (var(--lanes, 1) - 1)) / var(--lanes, 1));
	left: calc(var(--gutter-left) + var(--lane, 0) * (var(--lane-width) + var(--lane-gap)));
	width: var(--lane-width);
	display: flex;
	align-items: center;
	gap: .4rem;
	overflow: hidden;
	padding: .15rem .55rem;
	border-radius: var(--radius-sm);
	border-left: 3px solid var(--tide-700);
	background: var(--tide-100);
	color: var(--ink);
	text-decoration: none;
	font-size: .82rem;
	line-height: 1.2;
	transition: filter .12s ease;
}

.slot-entry:hover {
	filter: brightness(.97);
	color: var(--ink);
}

.slot-entry-time {
	font-weight: 800;
	white-space: nowrap;
	font-variant-numeric: tabular-nums;
}

.slot-entry-name {
	font-weight: 700;
	white-space: nowrap;
}

.slot-entry-owner {
	color: var(--ink-muted);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

.slot-entry-flag.flag-danger {
	background: var(--danger-bg);
	color: var(--danger-ink);
	font-weight: 800;
}

.slot-entry-flag {
	margin-left: auto;
	flex: none;
	background: var(--warn-bg);
	color: var(--warn-ink);
	border-radius: var(--radius-pill);
	padding: 0 .45rem;
	font-size: .68rem;
	font-weight: 700;
	white-space: nowrap;
}

.slot-entry-reason {
	color: var(--ink-muted);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/*
 * The colour of an appointment says what kind it is, when the clinic has chosen colours.
 * Every pair here is a light fill with a darker edge, so the ordinary text colour reads
 * on all of them — which is why the choice is a palette and not a colour picker.
 */
.slot-entry.colour-blue   { background: var(--appt-blue-fill); border-left-color: var(--appt-blue-edge); }
.slot-entry.colour-green  { background: var(--appt-green-fill); border-left-color: var(--appt-green-edge); }
.slot-entry.colour-amber  { background: var(--appt-amber-fill); border-left-color: var(--appt-amber-edge); }
.slot-entry.colour-red    { background: var(--appt-red-fill); border-left-color: var(--appt-red-edge); }
.slot-entry.colour-purple { background: var(--appt-purple-fill); border-left-color: var(--appt-purple-edge); }
.slot-entry.colour-teal   { background: var(--appt-teal-fill); border-left-color: var(--appt-teal-edge); }
.slot-entry.colour-pink   { background: var(--appt-pink-fill); border-left-color: var(--appt-pink-edge); }
.slot-entry.colour-grey   { background: var(--appt-grey-fill); border-left-color: var(--appt-grey-edge); }

/*
 * The status no longer takes the fill, because the fill now says what kind of appointment
 * it is and two meanings cannot share one colour. Seen is faded, in the room is outlined:
 * both read on top of any palette colour without arguing with it.
 */
.slot-entry.status-done {
	opacity: .55;
}

.slot-entry.status-in_progress {
	outline: 2px solid var(--warn-ink);
	outline-offset: -2px;
	font-weight: 700;
}

/*
 * The present minute on today's column (agenda-now.js). In the danger colour because it
 * is the one line on the diary that moves, with the time on a tab at its left end, over
 * the hour labels where it does not cover a name.
 */
.now-line {
	position: absolute;
	z-index: 5;
	left: 0;
	right: 0;
	height: 0;
	border-top: 2px solid var(--danger-ink);
	pointer-events: none;
}

.now-line::before {
	content: attr(data-time);
	position: absolute;
	left: .25rem;
	top: -.62rem;
	padding: 0 .3rem;
	border-radius: var(--radius-sm);
	background: var(--danger-ink);
	color: #fff;
	font-size: .66rem;
	font-weight: 800;
	line-height: 1.2rem;
	font-variant-numeric: tabular-nums;
}

.week-day .now-line::before {
	content: "";
	left: -.3rem;
	top: -.35rem;
	width: .6rem;
	height: .6rem;
	padding: 0;
	border-radius: 50%;
}

/* --- The midday closure --- */

/*
 * Drawn, but not offered. The hours between the shifts used to be a second box with its
 * own heading, which made one day look like two; they are now a shaded stretch of the
 * same column. Still unmistakably shut — a plain gap would read as free.
 */
.slot-closed {
	background: repeating-linear-gradient(
		45deg,
		var(--paper),
		var(--paper) 6px,
		var(--surface-sunken) 6px,
		var(--surface-sunken) 12px
	);
	cursor: default;
}

.closed-band {
	position: absolute;
	left: 0;
	right: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	pointer-events: none;
	font-size: .72rem;
	font-weight: 800;
	letter-spacing: .08em;
	text-transform: uppercase;
	color: var(--ink-muted);
}

.schedule {
	margin-bottom: 1.5rem;
}

.schedule-hours {
	margin: .1rem 0 .5rem;
	font-size: .85rem;
	font-weight: 600;
}

/* --- Choosing the colours --- */

.colour-choices {
	display: flex;
	flex-wrap: wrap;
	gap: .35rem;
}

/*
 * The radio itself is hidden and its label is the swatch, so the choice is made by
 * clicking the colour rather than a dot beside it. Hidden with opacity and not
 * display:none: a display:none control is skipped by the keyboard entirely, and this
 * still has to be reachable by tabbing.
 */
.colour-choices input {
	position: absolute;
	opacity: 0;
	width: 0;
	height: 0;
}

.colour-swatch {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2rem;
	height: 2rem;
	border-radius: var(--radius-sm);
	border: 2px solid transparent;
	cursor: pointer;
	font-size: .7rem;
	color: var(--ink-muted);
	margin: 0;
}

.colour-choices input:checked + .colour-swatch {
	border-color: var(--ink);
}

.colour-choices input:focus-visible + .colour-swatch {
	outline: 2px solid var(--focus);
	outline-offset: 2px;
}

.colour-swatch.swatch-none {
	background: var(--surface);
	border-style: dashed;
	border-color: var(--line-strong);
}

.colour-choices input:checked + .colour-swatch.swatch-none {
	border-style: solid;
	border-color: var(--ink);
}

.colour-swatch.swatch-blue   { background: var(--appt-blue-fill); box-shadow: inset 3px 0 0 var(--appt-blue-edge); }
.colour-swatch.swatch-green  { background: var(--appt-green-fill); box-shadow: inset 3px 0 0 var(--appt-green-edge); }
.colour-swatch.swatch-amber  { background: var(--appt-amber-fill); box-shadow: inset 3px 0 0 var(--appt-amber-edge); }
.colour-swatch.swatch-red    { background: var(--appt-red-fill); box-shadow: inset 3px 0 0 var(--appt-red-edge); }
.colour-swatch.swatch-purple { background: var(--appt-purple-fill); box-shadow: inset 3px 0 0 var(--appt-purple-edge); }
.colour-swatch.swatch-teal   { background: var(--appt-teal-fill); box-shadow: inset 3px 0 0 var(--appt-teal-edge); }
.colour-swatch.swatch-pink   { background: var(--appt-pink-fill); box-shadow: inset 3px 0 0 var(--appt-pink-edge); }
.colour-swatch.swatch-grey   { background: var(--appt-grey-fill); box-shadow: inset 3px 0 0 var(--appt-grey-edge); }

.colour-row {
	display: flex;
	align-items: center;
	gap: 1rem;
	flex-wrap: wrap;
	margin-bottom: .75rem;
}

.colour-row-name {
	flex: 0 0 9rem;
	font-size: .85rem;
	font-weight: 700;
}

/* --- The week --- */

/*
 * Wider than the rest of the application, and only here. Seven columns of diary do not
 * fit in the reading width the other screens use, and squeezing them there would leave
 * each day too narrow to show a name. Setting the variable rather than max-width is what
 * keeps the page centred in the room beside the sidebar.
 */
.content-wide {
	--content-max: 1440px;
}

.week-grid {
	display: flex;
	gap: .4rem;
	align-items: stretch;
}

/* The hour column carries no slots of its own, so it needs no border or background. */
.week-hours {
	flex: none;
	width: 3rem;
	border: none;
	background: none;
	box-shadow: none;
	margin-top: 1.9rem;
}

.week-hour {
	position: absolute;
	right: .4rem;
	font-size: .7rem;
	color: var(--ink-muted);
	text-align: right;
	font-variant-numeric: tabular-nums;
}

.week-day {
	flex: 1 1 0;
	min-width: 0;
}

.week-day-name {
	display: flex;
	align-items: baseline;
	justify-content: center;
	gap: .3rem;
	padding: .25rem;
	margin-bottom: .25rem;
	border-radius: var(--radius-md);
	text-decoration: none;
	color: var(--ink);
	font-size: .8rem;
	font-weight: 700;
	text-transform: capitalize;
}

.week-day-name:hover {
	background: var(--surface-sunken);
	color: var(--ink);
}

.week-day-name.is-today {
	background: var(--rose-100);
	color: var(--rose-700);
	font-weight: 800;
}

/* In a week column there is no room for the owner, so the entries are the animal alone. */
.week-day .slot-entry {
	--gutter-left: .2rem;
	--gutter-right: .2rem;
	--lane-gap: .15rem;
	font-size: .72rem;
	padding: .1rem .3rem;
	gap: .25rem;
}

.week-day .slot {
	padding-left: 0;
}

/*
 * Under a tablet the seven columns stop being readable, so the week scrolls sideways
 * rather than shrinking each day to a sliver. The day view is the one to use on a phone.
 */
@media (max-width: 900px) {
	.week {
		overflow-x: auto;
	}

	.week-grid {
		min-width: 820px;
	}
}

.hint-block {
	margin-top: 1.5rem;
	font-size: .9rem;
}

/* The date column should not stretch while the reason column takes the slack. */
.agenda th:first-child, .agenda td:first-child {
	width: 1%;
}

/* --- Clinical records --- */

.alert-warn {
	background: var(--warn-bg);
	color: var(--warn-ink);
	--alert-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7.5v5.5M12 16.5h.01'/%3E%3C/svg%3E");
}

.consultation {
	border-top: 1px solid var(--line);
	padding: 1.1rem 0;
}

.consultation:first-of-type {
	border-top: none;
	padding-top: .25rem;
}

/* A correction to an earlier note: marked down its edge, because it amends what is above. */
.consultation-correction {
	border-left: 3px solid var(--warn-ink);
	padding-left: .9rem;
}

.consultation-head {
	display: flex;
	align-items: center;
	gap: .75rem;
	flex-wrap: wrap;
	margin-bottom: .5rem;
	font-size: .88rem;
}

.consultation-date {
	font-weight: 800;
}

.consultation-body {
	margin: 0;
	display: grid;
	gap: .6rem;
}

.consultation-body dt {
	font-size: .72rem;
	text-transform: uppercase;
	letter-spacing: .07em;
	color: var(--ink-muted);
	font-weight: 800;
}

.consultation-body dd {
	margin: 0;
	white-space: pre-wrap;
}

/* The instructions the owner takes home: the part that must not be skimmed past. */
.consultation-body .home-care {
	background: var(--ok-bg);
	border-radius: var(--radius-md);
	padding: .7rem .85rem;
}

.consultation-body .home-care dt {
	color: var(--ok-ink);
}

.highlighted-field {
	background: var(--ok-bg);
	border-radius: var(--radius-md);
	padding: .85rem;
}

/* --- Attachments --- */

.attachment-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
	gap: 1rem;
	margin-top: 1rem;
}

.attachment {
	border: 1px solid var(--line);
	border-radius: var(--radius-md);
	overflow: hidden;
	text-decoration: none;
	color: inherit;
	display: flex;
	flex-direction: column;
	background: var(--surface);
	transition: border-color .12s ease, box-shadow .12s ease;
}

.attachment:hover {
	border-color: var(--tide-300);
	box-shadow: var(--shadow-md);
	color: inherit;
}

.attachment img {
	width: 100%;
	height: 130px;
	object-fit: cover;
	display: block;
	background: var(--ink);
}

.attachment-icon {
	height: 130px;
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--surface-sunken);
	font-weight: 800;
	color: var(--ink-muted);
	letter-spacing: .08em;
}

.attachment-meta {
	padding: .6rem .75rem;
	display: flex;
	flex-direction: column;
	gap: .15rem;
	font-size: .82rem;
}

input[type="file"] {
	padding: .4rem;
	font-size: .9rem;
}

/* --- Vaccination reminders --- */

.row-overdue td {
	background: var(--warn-bg);
}

.inline-label {
	margin-bottom: 0;
	white-space: nowrap;
	font-size: .85rem;
}

/*
 * A search bar with several filters in it — dates, a box, a wording — wraps onto more
 * lines on a phone; the one-box search does not need to and keeps its button beside it.
 * The selector repeats the global input rule's three :not() clauses because that rule
 * outweighs a plain ".search input", which is why the older width:auto below it never
 * took: the date boxes were full width and the whole bar slid off a 375px screen.
 */
.search.search-filters {
	flex-wrap: wrap;
}

.search.search-filters input:not([type="checkbox"]):not([type="radio"]):not(.visually-hidden),
.search.search-filters select {
	width: auto;
	flex: 0 1 auto;
	min-width: 0;
}

/* A label and its box, wrapping as one so a line break never parts them. */
.search-filters .filter {
	display: flex;
	align-items: center;
	gap: .6rem;
	flex: 0 1 auto;
	min-width: 0;
}

/*
 * Only the text box takes up slack; the dates and the wording are as wide as they are.
 * A small basis on purpose: wrapping is decided on the bases, before anything grows, and
 * a larger one pushed the button onto a line of its own at 1280px with room to spare.
 */
.search-filters .filter-grows {
	flex: 1 1 8rem;
}

.search-filters .filter-grows input[type="search"] {
	flex: 1 1 6rem;
}

.rule-chip {
	display: inline-block;
	margin-right: .5rem;
	white-space: nowrap;
}

.dose-status {
	display: flex;
	align-items: baseline;
	gap: .5rem;
	flex-wrap: wrap;
}

/* --- Animal search suggestions ------------------------------------------ */
/*
 * The list is deliberately uncapped: with 293 animals called Luna, stopping at ten
 * hides the one being looked for. Hence a max height and scrolling, rather than
 * trimming the query.
 */
.search {
	position: relative;
}

.suggestions {
	position: absolute;
	top: 100%;
	left: 0;
	z-index: 20;
	width: min(34rem, 100%);
	max-height: 22rem;
	overflow-y: auto;
	margin: 0.35rem 0 0;
	padding: .3rem;
	list-style: none;
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--radius-md);
	box-shadow: var(--shadow-lg);
}

.suggestions li + li {
	border-top: 1px solid var(--line);
}

.suggestions a {
	display: flex;
	align-items: baseline;
	gap: 0.5rem;
	padding: 0.5rem 0.75rem;
	border-radius: var(--radius-sm);
	text-decoration: none;
	color: inherit;
	font-weight: 700;
}

/* :focus as well as :hover — the list can be walked with the keyboard. */
.suggestions a:hover,
.suggestions a:focus {
	background: var(--tide-50);
	outline: none;
}

.suggestion-detail {
	color: var(--ink-muted);
	font-size: 0.875rem;
	font-weight: 400;
}

/*
 * The boxes that suggest vaccines and products from the official catalogue sit in narrow
 * columns, and official names run long and their ingredients longer. Side by side, the
 * name was squeezed into a column one word wide; here the ingredients go under it, two
 * lines at most.
 */
[data-catalogue-url] + .suggestions a {
	flex-direction: column;
	align-items: flex-start;
	gap: .15rem;
}

[data-catalogue-url] + .suggestions .suggestion-detail {
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 2;
	line-clamp: 2;
	overflow: hidden;
}

/* --- Patient photo ------------------------------------------------------- */
/*
 * Square and cropped rather than letterboxed: photos arrive in every shape a phone
 * produces, and a row of ragged rectangles reads worse than a consistent thumbnail.
 * The full picture is one click away through the attachment.
 */
.patient-photo {
	width: 96px;
	height: 96px;
	object-fit: cover;
	border-radius: var(--radius-lg);
	background: var(--surface-sunken);
	border: 3px solid var(--surface);
	box-shadow: var(--shadow-md);
}

.patient-photo-empty {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	background: var(--rose-100);
	color: var(--rose-600);
}

.patient-photo-empty .icon {
	width: 2.75rem;
	height: 2.75rem;
	stroke-width: 1.5;
}

/*
 * The file input itself is hidden and driven by its <label>, which is what allows a
 * button that looks like the others. Not display:none — that would take it out of the
 * tab order and off a screen reader entirely.
 */
.visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

/* --- The weight chart --- */

/*
 * Sized by its container rather than by the SVG's own coordinates, which is what the
 * viewBox is for. A fixed height keeps the card the same on every animal, whether the
 * history is three readings or three hundred.
 */
.weight-chart {
	margin: 0 0 1.25rem;
}

/*
 * Scaled uniformly, which is why there is no preserveAspectRatio="none" here any more.
 * Stretching the SVG to the width of the card squashed it vertically, and the points came
 * out as ovals — small, but it is the kind of thing that makes a chart look homemade.
 * Height follows from the viewBox, so everything stays the shape it was drawn.
 */
.weight-chart svg {
	width: 100%;
	height: auto;
	max-height: 320px;
}

.weight-axis {
	stroke: var(--line-strong);
	stroke-width: 1;
}

/*
 * vector-effect keeps the line one pixel thick after the SVG is stretched to the width
 * of the card. Without it the horizontal stretch thickens the stroke with everything
 * else and the line comes out fat and blurry.
 */
.weight-line {
	fill: none;
	stroke: var(--rose-600);
	stroke-width: 2.5;
	stroke-linejoin: round;
	vector-effect: non-scaling-stroke;
}

.weight-point {
	fill: var(--surface);
	stroke: var(--rose-600);
	stroke-width: 2;
	vector-effect: non-scaling-stroke;
}

.weight-point:hover {
	fill: var(--rose-600);
}

/*
 * The ruler, drawn faint. It has to be readable without competing with the line itself,
 * which is the thing somebody is actually looking at.
 */
.weight-grid {
	stroke: var(--line);
	stroke-width: 1;
	stroke-dasharray: 3 3;
	vector-effect: non-scaling-stroke;
}

.weight-tick-label,
.weight-date-label,
.weight-unit {
	fill: var(--ink-muted);
	font-size: 10px;
	font-family: inherit;
}

.weight-unit {
	font-weight: 800;
}

/* --- The shelf --- */

/* The sign is the information, so it is worth reading at a glance. */
.movement-in {
	color: var(--ok-ink);
}

.movement-out {
	color: var(--danger-ink);
}

/*
 * The warnings at the top of the shelf. A card rather than an alert bar: it can hold two
 * lists and several lines, and an alert that tall stops reading as an alert.
 */
.warnings h3 {
	font-size: .9rem;
	margin: 1rem 0 .35rem;
}

.warnings h3:first-of-type {
	margin-top: 0;
}

.warning-list {
	margin: 0;
	padding-left: 1.1rem;
	font-size: .9rem;
}

.warning-list li {
	margin-bottom: .2rem;
}

/* Out of stock and already expired are the two that cannot wait until tomorrow. */
.warning-out {
	color: var(--danger-ink);
	font-weight: 800;
}

/* --- Signed documents --- */

/* The wordings to pick from, as a row of buttons: one tap and the text appears. */
.choice-list {
	display: flex;
	flex-wrap: wrap;
	gap: .5rem;
}

/* The one already chosen, so the row says what the box below is. */
.button-chosen {
	background: var(--tide-700);
	color: #fff;
	border-color: transparent;
}

.button-chosen:hover {
	background: var(--tide-800);
	color: #fff;
}

/* The text being prepared: a document, so it reads like one rather than like a form box. */
.document-text {
	font-size: 1rem;
	line-height: 1.6;
}

/*
 * The frozen text, on the pad and on the record. pre-wrap keeps the vet's paragraphs and
 * blank lines exactly as written: this is the text somebody signed, and reflowing it
 * into one block is not the text somebody signed.
 */
.document-body {
	white-space: pre-wrap;
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--radius-lg);
	padding: 1.75rem 2rem;
	margin: 1rem 0 1.5rem;
	font-size: 1.05rem;
	line-height: 1.7;
	max-width: 46rem;
	box-shadow: var(--shadow-sm);
}

/*
 * The signing screen has no navigation bar. This is the sliver of chrome it keeps: the
 * name of the application and one way back for whoever works here.
 */
.signing-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: .6rem 1.25rem;
	background: var(--surface);
	border-bottom: 1px solid var(--line);
}

.signing-head .brand {
	display: block;
	line-height: 0;
}

.signing-head .brand img {
	width: 110px;
	height: auto;
}

.signing-head a {
	font-size: .9rem;
	font-weight: 700;
	text-decoration: none;
}

.signature-form {
	max-width: 46rem;
}

/* A label that is not a <label>: nothing focusable to point it at. */
.signature-form .label {
	display: block;
	margin-bottom: .35rem;
	font-size: .85rem;
	font-weight: 700;
}

/*
 * The pad. Tall enough for a real signature with a finger — a strip the height of a
 * text box produces a scrawl — and with a baseline drawn where the pen expects one.
 */
.signature-pad {
	position: relative;
	background: var(--surface);
	border: 2px dashed var(--line-strong);
	border-radius: var(--radius-lg);
	height: 14rem;
	touch-action: none;
}

.signature-pad canvas {
	display: block;
	width: 100%;
	height: 100%;
	cursor: crosshair;
	background:
		linear-gradient(var(--line-strong), var(--line-strong)) no-repeat 8% 78% / 84% 1px;
}

.signature-clear {
	position: absolute;
	top: .4rem;
	right: .75rem;
	font-size: .85rem;
}

/* The one button on the tablet that matters, sized for a thumb. */
.button-large {
	padding: .85rem 1.6rem;
	font-size: 1.1rem;
}

/* Signing on a printed copy instead: the same width as the pad, a step below it. */
.paper-signing {
	max-width: 46rem;
	margin-top: 1.5rem;
}

.paper-signing h2 {
	margin-top: 0;
	padding-top: 0;
	border-top: none;
	margin-bottom: .35rem;
}

/*
 * The lines on the printed copy. Drawn as borders rather than typed underscores, so they
 * all end at the same place whatever the label; the signature gets the tallest one.
 */
.paper-signature {
	max-width: 32rem;
	margin-top: 2.5rem;
}

.paper-line {
	display: flex;
	align-items: flex-end;
	gap: .75rem;
	margin: 0 0 1.75rem;
	height: 2rem;
}

.paper-line::after {
	content: "";
	flex: 1;
	border-bottom: 1px solid #000;
}

.paper-line-sign {
	height: 5rem;
}

.paper-line-short {
	max-width: 16rem;
}

.signing-discard {
	margin-top: 2.5rem;
	font-size: .85rem;
}

.signing-discard .link-button {
	color: var(--ink-muted);
	font-weight: 600;
}

/* The signature on the record, with who and when beside it. */
.signature-record {
	display: flex;
	flex-wrap: wrap;
	gap: 1.5rem 3rem;
	align-items: flex-start;
	max-width: 46rem;
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--radius-lg);
	padding: 1.25rem 1.5rem;
}

.signature-image {
	width: 18rem;
	max-width: 100%;
	border-bottom: 1px solid var(--line-strong);
}

/*
 * The document on an animal's file: a short list, the newest first, each one saying
 * whether it is still waiting on the tablet.
 */
.document-list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.document-list li {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: .25rem 1rem;
	padding: .55rem 0;
	border-top: 1px solid var(--line);
}

.document-list li:first-child {
	border-top: none;
}

/*
 * On paper only the document and the signature: no bar, no buttons, no card borders.
 * "Save as PDF" in the print dialog is how a copy leaves the building.
 */
/* Shown only on paper; see the print rules below. */
.print-only {
	display: none;
}

@media print {
	.app-nav, .topbar, .breadcrumb, .page-header .button, .flash, .no-print, .hero-mascot {
		display: none;
	}

	body {
		background: none;
	}

	.print-only {
		display: block;
	}

	.document-body, .signature-record {
		border: none;
		padding: 0;
		max-width: none;
		box-shadow: none;
	}

	.content,
	.app-nav ~ .content {
		max-width: none;
		margin: 0;
		padding: 0;
	}

	.page-hero {
		background: none;
		border: none;
		padding: 0;
		min-height: 0;
	}

	/*
	 * A printed sheet is a document, not a screenshot of one. The cards lose their
	 * frame and their fill — a box drawn round everything is how a screen groups
	 * things, and on paper the whitespace and the heading already do that — and a
	 * section is kept from being split across two pages.
	 */
	.card-block {
		border: none;
		background: none;
		padding: 0;
		margin-bottom: 1.5rem;
		break-inside: avoid;
		box-shadow: none;
	}

	/*
	 * The table loses its frame and its fills too: a tinted header band costs ink and
	 * says nothing that a rule under the words does not say better.
	 */
	.table {
		border: none;
		border-radius: 0;
		background: none;
		box-shadow: none;
	}

	.table th {
		background: none;
		color: inherit;
		border-bottom: 1px solid #000;
	}

	.print-heading {
		margin-bottom: .5rem;
		font-size: .9rem;
	}

	/*
	 * On paper the page is the frame, so the sheet drops its own and spreads out. The
	 * boxes round the number and round who it is billed to stay: those are rules the
	 * reader's eye follows, not decoration.
	 */
	.invoice-sheet {
		max-width: none;
		margin: 0;
		padding: 0;
		border: none;
		background: none;
		box-shadow: none;
	}

	.invoice-patient td {
		background: none;
		border-bottom: 1px solid #000;
	}

	.invoice-totals th {
		border-bottom: none;
	}
}

/* --- The clinic's logo --- */

.logo-form {
	margin-bottom: 1.25rem;
}

.logo-row {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 1.25rem;
}

/* The logo on a white tile the size it will roughly have on paper. */
.logo-preview {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 16rem;
	height: 6rem;
	padding: .75rem;
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--radius-md);
}

.logo-preview.is-empty {
	border-style: dashed;
	border-color: var(--line-strong);
}

.logo-preview img {
	max-width: 100%;
	max-height: 100%;
	object-fit: contain;
}

/* At the head of the invoice, above the clinic's name. */
.invoice-logo {
	display: block;
	max-width: 14rem;
	max-height: 5rem;
	object-fit: contain;
	object-position: left center;
	margin-bottom: .6rem;
}

/* --- The invoice --- */

/*
 * Laid out like the paper the clinic already hands over: issuer top left, the word
 * FACTURA and the number top right, who it is billed to underneath, the lines, and the
 * three figures at the bottom right. It is a document, so it keeps its frame on screen
 * and loses it on paper, where the page itself is the frame.
 */
.invoice-sheet {
	max-width: 48rem;
	margin: 0 auto;
	padding: 2.5rem;
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-md);
}

.invoice-head {
	display: flex;
	justify-content: space-between;
	align-items: flex-start;
	gap: 2rem;
	margin-bottom: 2rem;
}

/* The issuer block is a stack of short lines, which is why each span is its own row. */
.invoice-issuer {
	display: flex;
	flex-direction: column;
	gap: .1rem;
	font-size: .85rem;
	color: var(--ink-muted);
}

.invoice-clinic {
	font-size: 1.25rem;
	color: var(--ink);
	margin-bottom: .2rem;
}

.invoice-title {
	text-align: right;
}

/*
 * The VERI*FACTU block: "QR tributario:" over the code, the legend under it. The code is
 * held at 32 mm on paper, inside the 30 to 40 mm Hacienda asks for.
 */
.invoice-qr {
	flex: none;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: .2rem;
	text-align: center;
}

.invoice-qr-label {
	font-size: .72rem;
	font-weight: 700;
	color: var(--ink-muted);
}

.invoice-qr-code {
	width: 32mm;
	height: 32mm;
}

.invoice-qr-code svg {
	display: block;
	width: 100%;
	height: 100%;
}

.invoice-qr-legend {
	font-size: .8rem;
	font-weight: 800;
	letter-spacing: .05em;
}

.invoice-qr-note {
	max-width: 36mm;
	font-size: .62rem;
	line-height: 1.25;
	color: var(--ink-muted);
}

/* What a correcting invoice corrects, as a band under the parties. */
.invoice-rectifies {
	display: flex;
	flex-direction: column;
	gap: .15rem;
	margin-bottom: 1.5rem;
	padding: .75rem 1rem;
	border: 1px solid var(--line-strong);
	border-radius: var(--radius-md);
	font-size: .9rem;
}

/* The declaración responsable: label and value side by side, one fact per row. */
.facts {
	display: grid;
	gap: .5rem;
	margin: 0 0 1.5rem;
}

.facts > div {
	display: grid;
	grid-template-columns: minmax(10rem, 14rem) 1fr;
	gap: 1rem;
}

.facts dt {
	font-weight: 700;
	color: var(--ink-muted);
}

.facts dd {
	margin: 0;
}

@media (max-width: 40rem) {
	.facts > div {
		grid-template-columns: 1fr;
		gap: .1rem;
	}
}

/* Above the paper, on screen: where it stands with Hacienda, and the way to correct it. */
.invoice-status {
	max-width: 48rem;
	margin: 0 auto 1rem;
}

.invoice-status-line {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: .5rem;
	margin: 0 0 .75rem;
	font-size: .9rem;
}

.invoice-title h2 {
	margin: 0 0 .5rem;
	font-size: 1.6rem;
	letter-spacing: .08em;
	border: none;
	padding: 0;
}

.invoice-ref {
	display: flex;
	flex-direction: column;
	gap: .15rem;
	padding: .5rem .75rem;
	border: 1px solid var(--line);
	border-radius: var(--radius-md);
	font-size: .9rem;
}

.invoice-ref strong {
	font-size: 1.1rem;
}

.invoice-parties {
	display: flex;
	justify-content: space-between;
	gap: 2rem;
	margin-bottom: 1.5rem;
	padding: .9rem 1rem;
	border: 1px solid var(--line);
	border-radius: var(--radius-md);
}

.invoice-customer,
.invoice-vet {
	display: flex;
	flex-direction: column;
	gap: .1rem;
	font-size: .9rem;
}

.invoice-vet {
	text-align: right;
}

/* The small grey word over each block. */
.invoice-label {
	font-size: .72rem;
	font-weight: 800;
	text-transform: uppercase;
	letter-spacing: .07em;
	color: var(--ink-muted);
}

/* The animal, as a band across the line table rather than a column of its own. */
.invoice-patient td {
	background: var(--surface-sunken);
	font-size: .9rem;
}

.invoice-foot {
	display: flex;
	justify-content: space-between;
	align-items: flex-start;
	gap: 2rem;
	margin-top: 1.5rem;
}

.invoice-notes {
	flex: 1;
	display: flex;
	flex-direction: column;
	gap: .25rem;
	font-size: .9rem;
	min-height: 4rem;
}

.invoice-notes p {
	margin: 0;
}

/* The totals are a narrow table so the figures line up under each other. */
.invoice-totals {
	width: auto;
	min-width: 14rem;
	box-shadow: none;
}

.invoice-totals th {
	text-align: left;
	background: none;
	color: inherit;
}

/*
 * One column of numbers. The table's own cells are already right-aligned by .numeric,
 * and this keeps the totals block from stretching to the full width.
 */
.invoice-totals td {
	text-align: right;
	white-space: nowrap;
}

@media (max-width: 40rem) {
	.invoice-sheet {
		padding: 1.25rem;
	}

	.invoice-head,
	.invoice-parties,
	.invoice-foot {
		flex-direction: column;
		gap: 1rem;
	}

	.invoice-title,
	.invoice-vet {
		text-align: left;
	}
}

/* A form's first heading: .form h2 draws a rule above for a second section, not a first. */
.form .form-title {
	margin-top: 0;
	padding-top: 0;
	border-top: none;
}

/* --- The diary keeping itself up to date --- */

/*
 * The label under the diary's heading. Without a state nothing shows: a diary that is
 * not refreshing itself is the ordinary diary and does not need a label saying so.
 */
.live-status .live-on,
.live-status .live-off {
	display: none;
}

.live-status[data-live-state="on"] .live-on {
	display: inline;
}

.live-status[data-live-state="off"] .live-off {
	display: inline;
	color: var(--warn-ink);
}

/* A small dot before the words, green while connected. */
.live-status[data-live-state="on"] .live-on::before {
	content: "";
	display: inline-block;
	width: .5rem;
	height: .5rem;
	margin-right: .35rem;
	border-radius: 50%;
	background: var(--ok-ink);
	vertical-align: middle;
}

/* --- The diary per vet --- */

/* The filter sits under the day navigation, level with it, and only when it exists. */
.vet-filter {
	margin-bottom: 1.25rem;
	align-items: center;
}

/* flex: none, because .field grows to fill a form and this one is a label and a box. */
.vet-filter .field {
	display: flex;
	align-items: center;
	gap: .6rem;
	flex: none;
}

.vet-filter label {
	margin: 0;
	white-space: nowrap;
}

.vet-filter select {
	width: auto;
	min-width: 12rem;
}

.vet-filter .muted {
	font-size: .85rem;
}

/* Whose block it is, when the whole clinic is on screen at once. */
.slot-entry-vet {
	color: var(--ink-muted);
	font-size: .75rem;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* --- The review of the records --- */

.review-checks {
	list-style: none;
	margin: 0;
	padding: 0;
}

.review-checks li {
	display: flex;
	align-items: baseline;
	gap: 1rem;
	padding: .6rem 0;
	border-top: 1px solid var(--line);
}

.review-checks li:first-child {
	border-top: none;
}

/* The number first, wide enough for four digits so the titles line up. */
.review-count {
	flex: 0 0 3.2rem;
	text-align: right;
	font-size: 1.15rem;
	font-weight: 800;
	font-variant-numeric: tabular-nums;
}

.review-check {
	display: flex;
	flex-direction: column;
	gap: .1rem;
	min-width: 0;
}

.review-explanation {
	font-size: .85rem;
}

/* Looked for and not found: still listed, so nobody wonders whether it was checked. */
.review-clear .review-count,
.review-clear .review-check {
	color: var(--ink-muted);
}

/* --- The price list --- */

/* Money reads down a column, so it is right-aligned and the digits are the same width. */
.table th.numeric,
.table td.numeric {
	text-align: right;
	white-space: nowrap;
	font-variant-numeric: tabular-nums;
}

/* --- Bills --- */

/* The total reads as the answer to the column above it. */
.bill-total th,
.bill-total td {
	font-size: 1.05rem;
	font-weight: 800;
	border-top: 2px solid var(--line-strong);
}

/* What is still owed, said once and in colour, because it is the whole question. */
.bill-owing {
	font-size: 1.05rem;
	font-weight: 700;
	padding: .7rem .9rem;
	border-radius: var(--radius-md);
	margin: 0 0 1rem;
}

.bill-owing-open {
	background: var(--warn-bg);
	color: var(--warn-ink);
}

.bill-owing-clear {
	background: var(--ok-bg);
	color: var(--ok-ink);
}

/* What the search found, ready to put on the bill. */
.match-list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.match-list li {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	justify-content: space-between;
	gap: .75rem 1.5rem;
	padding: .75rem 0;
	border-top: 1px solid var(--line);
}

.match-list li:first-child {
	border-top: none;
}

.match-what {
	display: flex;
	flex-direction: column;
	gap: .15rem;
	min-width: 0;
}

.match-add {
	display: flex;
	align-items: flex-end;
	gap: .5rem;
}

.match-add label {
	display: flex;
	flex-direction: column;
	gap: .15rem;
	margin: 0;
	font-weight: 600;
	font-size: .8rem;
}

/* The three :not() clauses again: without them these come out full width. */
.match-add input:not([type="checkbox"]):not([type="radio"]):not(.visually-hidden) {
	width: 6rem;
}

/*
 * The discount on a bill line, typed in the row itself. The box keeps no border until
 * it is pointed at or being typed in, so a column of "0 %" reads as figures, not as a
 * form; a line with a discount shows its figure in the accent colour.
 */
.line-discount {
	display: flex;
	justify-content: flex-end;
	margin: 0;
}

.percent-input {
	position: relative;
	margin: 0;
}

.percent-input input:not([type="checkbox"]):not([type="radio"]):not(.visually-hidden) {
	width: 4.75rem;
	height: 2.1rem;
	padding: .25rem 1.5rem .25rem .5rem;
	text-align: right;
	border-color: transparent;
	/* A dashed line under it, the one hint that the figure can be typed over. */
	border-bottom: 1px dashed var(--line-strong);
	border-radius: var(--radius-sm);
	background: transparent;
	color: var(--ink-muted);
	box-shadow: none;
	-moz-appearance: textfield;
}

.percent-input input::-webkit-outer-spin-button,
.percent-input input::-webkit-inner-spin-button {
	-webkit-appearance: none;
	margin: 0;
}

.percent-input:hover input:not(.visually-hidden),
.percent-input input:focus {
	border: 1px solid var(--line-strong);
	background: var(--surface);
	color: var(--ink);
}

.percent-input.has-value input:not(.visually-hidden) {
	color: var(--tide-700);
	font-weight: 700;
}

.percent-input > span[aria-hidden] {
	position: absolute;
	right: .55rem;
	top: 50%;
	transform: translateY(-50%);
	color: var(--ink-muted);
	font-weight: 600;
	pointer-events: none;
}

/* The price before the discount, struck through above what is charged. */
.line-full-price {
	display: block;
	font-size: .8rem;
}
