/**
 * TopLife Management — the shared design system.
 *
 * WHAT THIS FILE IS FOR
 * ---------------------
 * There were three design systems. Each was internally consistent and none of
 * them agreed with the others: the lodge measured space in rem on a nine-step
 * scale, the hostel in pixels on a seven-step one, and the group in whatever
 * number was typed at the point of use. The lodge had a typographic scale; the
 * other two had none at all and silently inherited wp-admin's. Semantic states
 * were called `success`/`danger` in one file and `good`/`urgent` in another for
 * the same two colours.
 *
 * None of that was visible as a bug. It showed up as the three systems feeling
 * like three products from three companies, and as a change to "the card
 * radius" needing to be made three times and remembered three times.
 *
 * So: everything that is not identity lives here, once. Type, space, radius,
 * elevation, the neutral ramp, the semantic ramp, layout measurements and the
 * transition. All three scopes get them.
 *
 * WHAT THIS FILE IS DELIBERATELY NOT FOR
 * --------------------------------------
 * Identity. The lodge is teal, the hostel is indigo-slate, the group is a deep
 * green with a brass accent, and that is on purpose: a manager with three
 * systems open needs to know which one they are typing into from the corner of
 * their eye, before reading a word. `--tl-primary-*` and `--tl-accent-*` are
 * declared by each business's own stylesheet and are the only tokens that
 * differ between them.
 *
 * SCOPED, NOT ON :root
 * --------------------
 * These screens live inside wp-admin. Tokens on `:root` would be inherited by
 * every other plugin's screens on this installation, which is somebody else's
 * interface to change and not ours.
 *
 * THE PREFIX
 * ----------
 * `--tl-` reads as TopLife, not as Lodge. It was the lodge's prefix first
 * because the lodge was built first; promoting it costs the lodge nothing and
 * saves renaming four thousand lines that are already correct.
 *
 * @package LodgeStay_PMS
 */

.lspms,
.lshostel-app,
.lsgroup {

	/* -- Colour: neutrals ------------------------------------------------ */
	--tl-neutral-0:   #ffffff;
	--tl-neutral-25:  #fcfcfd;
	--tl-neutral-50:  #f7f8fa;
	--tl-neutral-100: #eef0f4;
	--tl-neutral-200: #e2e5eb;
	--tl-neutral-300: #cbd0da;
	--tl-neutral-400: #9aa2b1;
	--tl-neutral-500: #6b7484;
	--tl-neutral-600: #4d5462;
	--tl-neutral-700: #383e4a;
	--tl-neutral-800: #242933;
	--tl-neutral-900: #14181f;

	/*
	 * -- Colour: semantic -------------------------------------------------
	 *
	 * ONE NAME PER MEANING, AND THE MEANING IS THE NAME.
	 *
	 * The lodge called these success/warning/danger/info; the hostel called the
	 * same four good/warning/urgent/info, plus a fifth called notice. Both
	 * spellings are kept below and point at the same colours, because renaming
	 * every occurrence across six thousand lines of stylesheet is a change with
	 * a lot of surface and no benefit a person could see. What matters is that
	 * there is now one VALUE behind both names, so the two systems can no longer
	 * drift to slightly different reds.
	 */
	--tl-success-50:  #e9f7ef;
	--tl-success-100: #cdecda;
	--tl-success-500: #1e874b;
	--tl-success-700: #146036;

	--tl-warning-50:  #fdf4e3;
	--tl-warning-100: #fae7c2;
	--tl-warning-500: #b87a0b;
	--tl-warning-700: #8a5a06;

	--tl-danger-50:   #fdedec;
	--tl-danger-100:  #f9d6d3;
	--tl-danger-500:  #c0392b;
	--tl-danger-700:  #8f2a1f;

	--tl-info-50:     #eaf2fb;
	--tl-info-100:    #d0e2f6;
	--tl-info-500:    #2a6db5;
	--tl-info-700:    #1d4f85;

	/* The hostel's spellings, pointing at the same values. */
	--tl-good-50:     var(--tl-success-50);
	--tl-good-500:    var(--tl-success-500);
	--tl-good-700:    var(--tl-success-700);

	--tl-urgent-50:   var(--tl-danger-50);
	--tl-urgent-500:  var(--tl-danger-500);
	--tl-urgent-700:  var(--tl-danger-700);

	/*
	 * `notice` is the one state with no equivalent in the lodge's vocabulary:
	 * something worth reading that is neither good news nor a problem. It is a
	 * cool grey-blue rather than the info blue, so a notice does not read as
	 * loudly as a genuine informational callout.
	 */
	--tl-notice-50:   #eef2f8;
	--tl-notice-500:  #4a6285;
	--tl-notice-700:  #33455e;

	/*
	 * THE UNVERSIONED NAMES, WHICH WERE BEING ASKED FOR AND HAD NEVER EXISTED.
	 *
	 * Five declarations in this file and one in pms.css consume `--tl-info`,
	 * `--tl-good`, `--tl-urgent` and `--tl-ok-600` -- no step number. Every
	 * family above is defined WITH a step, so those four names resolved to
	 * nothing and rendered the literal in their own fallback: in light, which was
	 * harmless and invisible, and in DARK, where a literal chosen for white
	 * paper is a dark smear on a dark page. The proof screen's status marks and
	 * the permission matrix's ticks were doing exactly that.
	 *
	 * Defined here at the EXACT values those fallbacks already produced, so
	 * light mode does not move by a single byte, and overridden in
	 * inc/design/dark.php with the lifted ink steps so dark mode finally gets an
	 * answer instead of a leftover.
	 *
	 * `--tl-ok-600` is a name nothing else in the platform uses; it is kept
	 * rather than renamed because renaming it is a change to pms.css that buys
	 * nothing today, and defining it is what stops it rendering a light literal
	 * on a dark page.
	 */
	--tl-info:        #2563eb;
	--tl-good:        #15803d;
	--tl-urgent:      #b91c1c;
	--tl-ok-600:      #1c6b41;

	/*
	 * Three more that dark.php defines and light never did, so light has always
	 * rendered the literal in each `var()`'s own fallback. Phase 1 noticed two of
	 * them (`--tl-ink-2`, `--tl-ink-3`) and gave them dark values, correctly, but
	 * defining a token in one theme and not the other leaves the other theme
	 * outside the system rather than in it.
	 *
	 * Written at EXACTLY the values those fallbacks produce, so nothing on any
	 * light screen moves. What changes is that a Customizer edit to the neutrals
	 * can now reach them, which is the entire point of a token.
	 */
	--tl-surface-sunken: #f7f8f9;
	--tl-ink-2:          #4a5654;
	--tl-ink-3:          #74807e;

	/*
	 * `--tl-text-2` is consumed with `var(--tl-neutral-700)` behind it; named
	 * here as that same neutral rather than as a copy of its hex, so the two
	 * cannot drift.
	 */
	--tl-text-2:      var(--tl-neutral-700);

	/*
	 * `--tl-muted` is the one entry in this block that CHANGES a light-mode
	 * pixel, and it is a correction rather than a preference.
	 *
	 * `pms.css` line ~4860 says `color: var(--tl-muted)` with NO fallback, on the
	 * caption under a room that has no photograph. An undefined custom property
	 * with no fallback makes the whole declaration invalid at computed-value
	 * time, so `color` fell back to `inherit` and that caption has been rendering
	 * at FULL ink -- the one place in the interface asking to be quiet was the
	 * loudest thing in the panel. Dark mode was unaffected, because dark.php
	 * defines the name.
	 *
	 * Pointed at the muted ink the rest of the platform uses, which is what the
	 * declaration was asking for. One caption, one screen, reported rather than
	 * slipped in.
	 */
	--tl-muted:       var(--tl-text-muted);

	/* -- Surfaces -------------------------------------------------------- */
	--tl-bg:            var(--tl-neutral-50);
	--tl-surface:       var(--tl-neutral-0);
	--tl-surface-2:     var(--tl-neutral-25);
	--tl-border:        var(--tl-neutral-200);
	--tl-border-strong: var(--tl-neutral-300);

	/* -- Text ------------------------------------------------------------ */
	--tl-text:        var(--tl-neutral-800);
	--tl-text-muted:  var(--tl-neutral-500);
	--tl-text-subtle: var(--tl-neutral-400);
	--tl-text-invert: var(--tl-neutral-0);

	/* -- Typography ------------------------------------------------------ */
	--tl-font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
		"Helvetica Neue", Arial, sans-serif;
	--tl-font-num: "SF Mono", ui-monospace, "Cascadia Mono", Menlo, Consolas, monospace;

	--tl-size-xs:   0.75rem;   /* 12 — table meta, counts             */
	--tl-size-sm:   0.8125rem; /* 13 — secondary body, table cells    */
	--tl-size-base: 0.875rem;  /* 14 — body                           */
	--tl-size-md:   1rem;      /* 16 — card titles                    */
	--tl-size-lg:   1.125rem;  /* 18 — section headings               */
	--tl-size-xl:   1.375rem;  /* 22 — page title                     */
	--tl-size-2xl:  1.75rem;   /* 28 — KPI figures                    */
	--tl-size-3xl:  2.25rem;   /* 36 — hero figures                   */

	--tl-lh-tight: 1.2;
	--tl-lh-snug:  1.35;
	--tl-lh-base:  1.55;

	--tl-weight-regular: 400;
	--tl-weight-medium:  500;
	--tl-weight-semi:    600;
	--tl-weight-bold:    700;

	/*
	 * The monospace stack. `pms.css` asks for `--tl-mono` when it prints a
	 * receipt reference or a figure that has to align in a column; the token was
	 * never defined, so it has always used the literal stack in its own
	 * fallback. Same stack, named once.
	 */
	--tl-mono: ui-monospace, SFMono-Regular, Menlo, monospace;

	/* -- Spacing: a 4px base, so everything lines up on a common grid ---- */
	--tl-space-1:  0.25rem;  /*  4 */
	--tl-space-2:  0.5rem;   /*  8 */
	--tl-space-3:  0.75rem;  /* 12 */
	--tl-space-4:  1rem;     /* 16 */
	--tl-space-5:  1.25rem;  /* 20 */
	--tl-space-6:  1.5rem;   /* 24 */
	--tl-space-8:  2rem;     /* 32 */
	--tl-space-10: 2.5rem;   /* 40 */
	--tl-space-12: 3rem;     /* 48 */

	/* -- Radius: controlled, not pill-shaped ----------------------------- */
	--tl-radius-sm:   4px;
	--tl-radius:      8px;
	--tl-radius-md:   10px;
	--tl-radius-lg:   14px;
	--tl-radius-full: 999px;

	/* -- Elevation: tight and low-opacity ------------------------------- */
	--tl-shadow-xs: 0 1px 2px rgba(20, 24, 31, 0.04);
	--tl-shadow-sm: 0 1px 2px rgba(20, 24, 31, 0.05), 0 1px 3px rgba(20, 24, 31, 0.04);
	--tl-shadow-md: 0 2px 4px rgba(20, 24, 31, 0.05), 0 4px 12px rgba(20, 24, 31, 0.06);
	--tl-shadow-lg: 0 8px 24px rgba(20, 24, 31, 0.10), 0 2px 6px rgba(20, 24, 31, 0.05);

	/*
	 * The measurements the whole layout hangs off. Stated once so a change to
	 * any of them moves the sidebar, the brand block, the top bar and the
	 * sticky offsets together rather than one of them drifting.
	 */
	--tl-sidebar-w:  264px;
	--tl-topbar-h:   68px;
	--tl-measure:    1440px;
	/*
	 * The full-width counterpart. `toplife.css` was already asking for
	 * `--tl-measure-wide` and no such token existed, so that rule had been
	 * silently rendering its 100% fallback since the day it was written. Named
	 * here at the value it has always resolved to, so nothing moves and the
	 * request now reaches something.
	 */
	--tl-measure-wide: 100%;
	--tl-transition: 140ms cubic-bezier(0.4, 0, 0.2, 1);

	/*
	 * The smallest a touch target may be. Named rather than repeated, because
	 * it is an accessibility floor and a floor that appears in forty places
	 * gets raised in thirty-nine of them.
	 */
	--tl-touch: 44px;
}

/*
 * THE ONE THING THIS FILE SETS RATHER THAN DECLARES.
 *
 * Type. The lodge already applied its own font; the hostel and the group
 * inherited wp-admin's, which is why the three read as different products even
 * where the layouts matched. Applying it here is what actually makes them one
 * platform, and it is applied to the scope root only — every rule inside each
 * stylesheet goes on deciding its own size and weight.
 */
.lspms,
.lshostel-app,
.lsgroup {
	font-family: var(--tl-font);
	font-size: var(--tl-size-base);
	line-height: var(--tl-lh-base);
	-webkit-font-smoothing: antialiased;
}

/*
 * Numbers in a table or a KPI need to line up under each other. Tabular figures
 * do that without a monospace face, so a column of money stays readable rather
 * than turning into code.
 */
.lspms .lspms-kpi__value,
.lspms .lspms-metric__value,
.lshostel-app .lshostel-kpi__value,
.lsgroup .lsgroup-figure__value {
	font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   SHARED BEHAVIOUR
   ==========================================================================

   Three things every screen in all three systems must do, written once. They
   are behaviour rather than decoration, which is why they are not left to each
   business's stylesheet to remember.
   ========================================================================== */

/*
 * 1. A visible focus ring, on all three, in the business's own colour.
 *
 * wp-admin's default focus style is a blue shadow that disappears against the
 * lodge's teal and the group's green. Somebody navigating by keyboard must be
 * able to see where they are.
 */
.lspms :focus-visible,
.lshostel-app :focus-visible,
.lsgroup :focus-visible {
	outline: 2px solid var(--tl-primary-500, #1f7376);
	outline-offset: 2px;
	border-radius: var(--tl-radius-sm);
}

/*
 * 2. Wide content scrolls inside its own box, never the page.
 *
 * A table with eleven columns on a 320px phone has to go somewhere. It goes
 * sideways inside its own container, so the PAGE never scrolls horizontally —
 * which is the thing that makes an interface feel broken rather than dense.
 */
/*
 * EVERY SCROLL CLASS UNDER EVERY SCOPE, AND WHY THAT IS NOT PARANOIA.
 *
 * This used to pair each business's scroll class with only its own scope:
 * `.lspms .lspms-scroll`, `.lshostel-app .lshostel-scroll`, and so on. That is
 * correct for anything a single business draws, and wrong the moment a SHARED
 * component is drawn inside two of them.
 *
 * The dashboard settings panel is exactly that. One file draws it for all three
 * businesses and it emits `lspms-scroll` wherever it lands — so inside
 * `.lsgroup` and inside `.lshostel-app` the selector matched nothing, the box
 * kept `overflow-x: visible`, and its 480px table pushed the whole page
 * sideways. Found on the deployed group screen at 320, 375 and 414px; the
 * hostel had the same fault and it was invisible only because its panel starts
 * collapsed.
 *
 * The scoping is still real — nothing here applies outside the three systems —
 * but which of the three a scroll box happens to be standing in is not a fact
 * the rule should depend on.
 */
.lspms .lspms-scroll,
.lspms .lshostel-scroll,
.lspms .lsgroup-scroll,
.lshostel-app .lspms-scroll,
.lshostel-app .lshostel-scroll,
.lshostel-app .lsgroup-scroll,
.lsgroup .lspms-scroll,
.lsgroup .lshostel-scroll,
.lsgroup .lsgroup-scroll {
	-webkit-overflow-scrolling: touch;
	max-width: 100%;
	overflow-x: auto;
}

/*
 * Bank details, wherever a business shows where it is paid.
 *
 * In the shared stylesheet rather than in one business's, because the same
 * block appears on the lodge, on the hostel and on a receipt, and three copies
 * of a layout carrying an account number is three chances for one of them to
 * wrap a digit onto its own line.
 */
.lspms .lspms-bank,
.lshostel-app .lspms-bank,
.lsgroup .lspms-bank {
	display: grid;
	gap: var(--tl-space-2);
	margin: 0 0 var(--tl-space-3);
	padding: var(--tl-space-4);
	border: 1px solid var(--tl-neutral-200);
	border-radius: var(--tl-radius);
	background: var(--tl-surface-sunken, #f7f8f9);
	max-width: 100%;
}

.lspms-bank__row {
	display: grid;
	grid-template-columns: minmax(0, 10rem) minmax(0, 1fr);
	gap: var(--tl-space-2);
	align-items: baseline;
}

.lspms-bank__row dt {
	font-size: var(--tl-size-xs);
	font-weight: var(--tl-weight-medium);
	color: var(--tl-neutral-600);
}

.lspms-bank__row dd {
	margin: 0;
	font-weight: var(--tl-weight-semi, 600);
	/*
	 * Tabular figures and a wrap that breaks anywhere: an account number is
	 * read a digit at a time and copied by hand, so it must not be re-flowed
	 * into something a reader could mis-transcribe, and must not push the card
	 * wider than its column on a phone.
	 */
	font-variant-numeric: tabular-nums;
	overflow-wrap: anywhere;
}

.lspms-bank__note {
	margin: 0 0 var(--tl-space-3);
	max-width: var(--tl-measure, 70ch);
	font-size: var(--tl-size-xs);
	line-height: 1.55;
	color: var(--tl-neutral-600);
}

.lspms-bank--unset {
	margin: 0 0 var(--tl-space-3);
	padding: var(--tl-space-3);
	border: 1px dashed var(--tl-neutral-300);
	border-radius: var(--tl-radius);
	color: var(--tl-neutral-600);
	font-size: var(--tl-size-xs);
}

@media screen and (max-width: 480px) {
	/* The label sits above the value rather than squeezing it to a column. */
	.lspms-bank__row { grid-template-columns: minmax(0, 1fr); gap: 2px; }
}

/*
 * 3. Motion is a preference, not a decision this interface gets to make.
 */
@media (prefers-reduced-motion: reduce) {
	.lspms *,
	.lshostel-app *,
	.lsgroup * {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		scroll-behavior: auto !important;
		transition-duration: 0.01ms !important;
	}
}

/*
 * A touch target floor on the controls a person actually taps. Applied to the
 * three systems' buttons and links-styled-as-buttons rather than to everything,
 * because forcing 44px onto a table row's inline "Edit" link would make a
 * twelve-row table three screens long.
 */
@media (pointer: coarse) {
	.lspms .button,
	.lspms .lspms-btn,
	.lshostel-app .button,
	.lshostel-app .lshostel-btn,
	.lsgroup .button,
	.lsgroup .lsgroup-btn {
		min-height: var(--tl-touch);
	}
}

/* ==========================================================================
   THE DASHBOARD GRID
   ==========================================================================

   Shared by all three systems, because a block registered against any of them
   is drawn by the same renderer and has to tile the same way.

   Twelve columns, and a block declares how many it wants. The widths on offer
   are quarter, third, half and full — four choices that tile cleanly at every
   breakpoint rather than twelve that let somebody build a row which does not
   add up.
   ========================================================================== */

.lspms-blocks {
	display: grid;
	gap: var(--tl-space-5);
	grid-template-columns: repeat(12, minmax(0, 1fr));
	margin: var(--tl-space-5) 0;
}

/*
 * `minmax(0, 1fr)` above and `min-width: 0` here are the pair that stops a wide
 * child — a table, a chart, a long unbroken reference — forcing its column
 * wider than the grid and pushing the whole page sideways. A grid item's default
 * minimum is its CONTENT's width, not zero, which is the single most common
 * cause of a dashboard that scrolls horizontally on a phone.
 */
.lspms-blocks__item {
	min-width: 0;
}

.lspms-blocks__item--3  { grid-column: span 3; }
.lspms-blocks__item--4  { grid-column: span 4; }
.lspms-blocks__item--6  { grid-column: span 6; }
.lspms-blocks__item--12 { grid-column: span 12; }

/*
 * Below a tablet, a quarter-width block is a column too narrow to read a number
 * in. Widths collapse in two steps rather than one so a half-width pair still
 * sits side by side on a tablet, which is where they were designed to.
 */
@media (max-width: 1024px) {
	.lspms-blocks__item--3 { grid-column: span 6; }
	.lspms-blocks__item--4 { grid-column: span 6; }
}

@media (max-width: 782px) {
	.lspms-blocks {
		gap: var(--tl-space-4);
	}

	.lspms-blocks__item--3,
	.lspms-blocks__item--4,
	.lspms-blocks__item--6 {
		grid-column: span 12;
	}
}

/* -- Configuring what is on it -------------------------------------------- */

.lspms-dashsettings {
	background: var(--tl-surface);
	border: 1px solid var(--tl-border);
	border-radius: var(--tl-radius);
	margin: var(--tl-space-6) 0;
	padding: var(--tl-space-4);
}

.lspms-dashsettings__summary {
	cursor: pointer;
	font-size: var(--tl-size-md);
	font-weight: var(--tl-weight-semi);
	list-style: none;
}

.lspms-dashsettings__summary::-webkit-details-marker { display: none; }

.lspms-dashsettings__summary::after {
	content: "";
	display: inline-block;
	margin-left: var(--tl-space-2);
	border-left: 4px solid transparent;
	border-right: 4px solid transparent;
	border-top: 5px solid currentColor;
	vertical-align: middle;
}

.lspms-dashsettings[open] > .lspms-dashsettings__summary::after {
	transform: rotate(180deg);
}

.lspms-dashsettings__note {
	color: var(--tl-text-muted);
	font-size: var(--tl-size-sm);
	margin: var(--tl-space-3) 0 var(--tl-space-4);
	max-width: 62ch;
}

.lspms-dashsettings__table {
	border-collapse: collapse;
	width: 100%;
}

.lspms-dashsettings__table th,
.lspms-dashsettings__table td {
	border-bottom: 1px solid var(--tl-border);
	padding: var(--tl-space-2) var(--tl-space-3);
	text-align: left;
	vertical-align: middle;
}

.lspms-dashsettings__table th {
	color: var(--tl-text-muted);
	font-size: var(--tl-size-xs);
	font-weight: var(--tl-weight-semi);
	letter-spacing: 0.04em;
	text-transform: uppercase;
}

/*
 * The row is also the JS hook for moving a block, so it needs a rule as well as
 * a name: a class the markup emits and the stylesheet has never heard of is
 * either dead or a hook, and there is no way to tell which from the outside.
 * This one is a hook, and it earns its rule by making the row you just moved
 * visible for a moment.
 */
.lspms-dashsettings__row:focus-within {
	background: var(--tl-surface-2);
}

.lspms-dashsettings__hint {
	color: var(--tl-text-muted);
	display: block;
	font-size: var(--tl-size-xs);
}

.lspms-dashsettings__move {
	white-space: nowrap;
}

.lspms-dashsettings__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--tl-space-2);
	margin: var(--tl-space-4) 0 0;
}

/*
 * The table is the one thing on this panel that can outgrow a phone: four
 * columns, one of them a select. It sits inside a `.lspms-scroll` wrapper —
 * the project's own convention, rather than a second mechanism — so it scrolls
 * inside its own box and never takes the page with it.
 */
@media (max-width: 600px) {
	.lspms-dashsettings__table {
		min-width: 480px;
	}
}

/*
 * ---------------------------------------------------------------------------
 * PAYMENT VERIFICATION
 * ---------------------------------------------------------------------------
 *
 * One screen serves both businesses, so its rules live here rather than in
 * either business's own stylesheet. The scope selectors below are the same nine
 * pairings the scroll boxes use, and for the same reason: which of the three
 * shells a shared component happens to be standing in is not a fact the rule
 * should depend on.
 */
.lspms .lspms-proof__lead,
.lshostel-app .lspms-proof__lead,
.lsgroup .lspms-proof__lead {
	max-width: var(--tl-measure, 70ch);
	margin: 0 0 var(--tl-space-4);
	color: var(--tl-neutral-600);
	line-height: 1.55;
}

.lspms .lspms-proof__heading,
.lshostel-app .lspms-proof__heading,
.lsgroup .lspms-proof__heading {
	margin: var(--tl-space-6) 0 var(--tl-space-4);
	font-size: var(--tl-size-md, 1rem);
	font-weight: var(--tl-weight-semi, 600);
}

/*
 * Four figures that must stay four figures on a phone rather than becoming a
 * column of full-width cards. auto-fit with a floor of 10rem gives two across
 * at 375px and four at 1024px without a single media query.
 */
.lspms .lspms-proof__cards,
.lshostel-app .lspms-proof__cards,
.lsgroup .lspms-proof__cards {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
	gap: var(--tl-space-3);
	margin: 0 0 var(--tl-space-5);
}

.lspms-proof__card {
	display: grid;
	/*
	 * A label, a figure and a count at 2px apart read as three lines of one
	 * paragraph. The figure is the thing being looked up; it gets a step of its
	 * own so the eye can land on it without reading the label first.
	 */
	gap: var(--tl-space-1);
	padding: var(--tl-space-4);
	border: 1px solid var(--tl-neutral-200);
	border-radius: var(--tl-radius);
	background: var(--tl-surface-sunken, #f7f8f9);
	min-width: 0;
}

.lspms-proof__card-label {
	font-size: var(--tl-size-xs);
	color: var(--tl-neutral-600);
}

.lspms-proof__card-value {
	font-size: var(--tl-size-xl, 1.5rem);
	font-weight: var(--tl-weight-semi, 600);
	line-height: 1.15;
	letter-spacing: -0.018em;
	font-variant-numeric: tabular-nums;
	overflow-wrap: anywhere;
}

.lspms-proof__card-count {
	font-size: var(--tl-size-xs);
	color: var(--tl-neutral-500, #6b7280);
}

/*
 * Eight columns of dates, names, money and controls. It does not fit a phone
 * and is not meant to: it sits inside the scroll box its caller opens, so it
 * scrolls in its own box rather than taking the page sideways with it.
 */
.lspms .lspms-proof__table,
.lshostel-app .lspms-proof__table,
.lsgroup .lspms-proof__table {
	width: 100%;
	min-width: 60rem;
	border-collapse: collapse;
	font-size: var(--tl-size-xs);
}

.lspms-proof__table th,
.lspms-proof__table td {
	padding: var(--tl-space-2) var(--tl-space-3);
	text-align: left;
	vertical-align: top;
	border-bottom: 1px solid var(--tl-neutral-200);
}

.lspms-proof__table th {
	font-weight: var(--tl-weight-semi, 600);
	color: var(--tl-neutral-600);
	white-space: nowrap;
}

/*
 * The reason a payment was refused, on its own full-width row under the one it
 * belongs to. In the table rather than in a tooltip because it is the single
 * most important thing on a rejected row: it is what the payer has to be told.
 */
.lspms-proof__reason {
	/*
	 * A row of its own rather than a cell in the row above, so the reason can
	 * run the full width of the table instead of being wrapped into whatever
	 * the narrowest column happens to be.
	 */
	background: var(--tl-surface-sunken, #f7f8f9);
}

.lspms-proof__reason td {
	padding-top: 0;
	color: var(--tl-neutral-600);
	font-style: normal;
	background: var(--tl-surface-sunken, #f7f8f9);
}

.lspms-proof__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--tl-space-2);
	align-items: flex-start;
}

.lspms-proof__form {
	display: flex;
	flex-wrap: wrap;
	gap: var(--tl-space-2);
	align-items: center;
	margin: 0;
}

.lspms-proof__input {
	min-width: 0;
	width: 14rem;
	max-width: 100%;
}

.lspms-proof__note {
	display: inline-block;
	max-width: 22rem;
	color: var(--tl-neutral-600);
}

.lspms .lspms-proof__empty,
.lshostel-app .lspms-proof__empty,
.lsgroup .lspms-proof__empty {
	padding: var(--tl-space-4);
	border: 1px dashed var(--tl-neutral-300);
	border-radius: var(--tl-radius);
	background: var(--tl-surface-sunken, #f7f8f9);
}

.lspms-proof__empty-heading {
	margin: 0 0 var(--tl-space-2);
	font-weight: var(--tl-weight-semi, 600);
}

.lspms-proof__empty-body {
	margin: 0;
	max-width: var(--tl-measure, 70ch);
	color: var(--tl-neutral-600);
	line-height: 1.55;
}

/*
 * FACT / ANALYSIS / RECOMMENDATION, on a shared screen.
 *
 * The group view has its own version of this under `.lsgroup-claim`. Two
 * implementations of one idea is untidy and it is deliberate for now:
 * consolidating them means renaming a class on a screen this pass is not about,
 * and a payment pass is the wrong place to repaint the group dashboard.
 */
.lspms .lspms-claim,
.lshostel-app .lspms-claim,
.lsgroup .lspms-claim {
	display: grid;
	grid-template-columns: auto auto minmax(0, 1fr);
	gap: var(--tl-space-2);
	align-items: baseline;
	margin: 0 0 var(--tl-space-2);
	padding: var(--tl-space-2) var(--tl-space-3);
	border-left: 3px solid var(--tl-neutral-300);
	background: var(--tl-surface-sunken, #f7f8f9);
	font-size: var(--tl-size-xs);
	line-height: 1.55;
}

.lspms-claim__mark {
	font-size: 16px;
	width: 16px;
	height: 16px;
	color: var(--tl-neutral-600);
}

.lspms-claim__kind {
	font-weight: var(--tl-weight-semi, 600);
	letter-spacing: 0.04em;
	white-space: nowrap;
	color: var(--tl-neutral-600);
}

.lspms-claim__text {
	min-width: 0;
	overflow-wrap: anywhere;
}

/* A measurement, a reading of it, and a suggestion each read differently. */
.lspms-claim--fact { border-left-color: var(--tl-neutral-400, #9ca3af); }
.lspms-claim--analysis { border-left-color: var(--tl-info, #2563eb); }
.lspms-claim--recommendation { border-left-color: var(--tl-good, #15803d); }
.lspms-claim--insufficient { border-left-color: var(--tl-neutral-300); }

@media screen and (max-width: 600px) {
	/*
	 * The label moves above the sentence rather than squeezing it into a
	 * column two words wide.
	 */
	.lspms .lspms-claim,
	.lshostel-app .lspms-claim,
	.lsgroup .lspms-claim {
		grid-template-columns: auto minmax(0, 1fr);
	}

	.lspms-claim__text {
		grid-column: 1 / -1;
	}
}

/*
 * ---------------------------------------------------------------------------
 * PAYMENT VERIFICATION, PART TWO: FILTERS, DETAIL AND INSTRUCTIONS
 * ---------------------------------------------------------------------------
 */

/*
 * The filter row. One line on a desktop, wrapping to as many as it needs on a
 * phone, with each control keeping a floor wide enough to type a date into.
 */
.lspms .lspms-proof__filters,
.lshostel-app .lspms-proof__filters,
.lsgroup .lspms-proof__filters {
	display: flex;
	flex-wrap: wrap;
	gap: var(--tl-space-3);
	align-items: flex-end;
	/*
	 * SEPARATED FROM THE SUMMARY ABOVE IT, BECAUSE IT IS A DIFFERENT KIND OF
	 * THING.
	 *
	 * The cards report what is true. The filters change what is shown. Sitting
	 * one directly under the other in the same sunken box, four rules apart,
	 * they read as one long control panel and the reader has to work out which
	 * half is which. A larger gap above and a heading-sized step below is all
	 * that is needed to say "this is where you ask a question".
	 */
	margin: 0 0 var(--tl-space-6);
	padding: var(--tl-space-4);
	border: 1px solid var(--tl-neutral-200);
	border-radius: var(--tl-radius);
	background: var(--tl-surface-sunken, #f7f8f9);
}

.lspms-proof__filter {
	display: grid;
	gap: var(--tl-space-1);
	margin: 0;
	min-width: 0;
	flex: 1 1 9rem;
}

.lspms-proof__filter label {
	font-size: var(--tl-size-xs);
	color: var(--tl-neutral-600);
}

.lspms-proof__filter input,
.lspms-proof__filter select {
	width: 100%;
	min-width: 0;
	max-width: 100%;
}

.lspms-proof__filter--go {
	display: flex;
	gap: var(--tl-space-2);
	align-items: center;
	flex: 0 0 auto;
}

/* A KPI card carries its state's own mark, so the row is not read by colour. */
.lspms-proof__card-mark {
	font-size: 15px;
	width: 15px;
	height: 15px;
	margin-inline-end: 4px;
	vertical-align: -2px;
}

.lspms-proof__card-mark--good { color: var(--tl-good, #15803d); }
.lspms-proof__card-mark--warning { color: var(--tl-warning, #b45309); }
.lspms-proof__card-mark--urgent { color: var(--tl-urgent, #b91c1c); }
.lspms-proof__card-mark--notice { color: var(--tl-neutral-500, #6b7280); }
.lspms-proof__card-mark--info { color: var(--tl-info, #2563eb); }
.lspms-proof__card-mark--neutral { color: var(--tl-neutral-500, #6b7280); }

/* The two running totals sit apart from the six state counts. */
.lspms-proof__cards--totals {
	border-top: 1px solid var(--tl-neutral-200);
	padding-top: var(--tl-space-3);
}

/*
 * One submission in full. Label and value in two columns on a desktop, stacked
 * on a phone, and the value free to wrap: a bank reference is long and must not
 * push the page sideways.
 */
.lspms .lspms-proof__detail,
.lshostel-app .lspms-proof__detail,
.lsgroup .lspms-proof__detail {
	display: grid;
	gap: 0;
	margin: 0 0 var(--tl-space-4);
	border: 1px solid var(--tl-neutral-200);
	border-radius: var(--tl-radius);
	overflow: hidden;
	max-width: 100%;
}

.lspms-proof__detail-row {
	display: grid;
	grid-template-columns: minmax(0, 14rem) minmax(0, 1fr);
	gap: var(--tl-space-3);
	padding: var(--tl-space-2) var(--tl-space-3);
	border-bottom: 1px solid var(--tl-neutral-200);
}

.lspms-proof__detail-row:last-child { border-bottom: 0; }

.lspms-proof__detail-row dt {
	margin: 0;
	font-size: var(--tl-size-xs);
	color: var(--tl-neutral-600);
}

.lspms-proof__detail-row dd {
	margin: 0;
	min-width: 0;
	overflow-wrap: anywhere;
	font-variant-numeric: tabular-nums;
}

/*
 * The decision panel. Bordered and separated because what is inside it moves
 * money, and it should not read as more of the page above it.
 */
.lspms .lspms-proof__panel,
.lshostel-app .lspms-proof__panel,
.lsgroup .lspms-proof__panel {
	display: grid;
	gap: var(--tl-space-3);
	margin: 0 0 var(--tl-space-4);
	padding: var(--tl-space-4);
	border: 1px solid var(--tl-neutral-300);
	border-radius: var(--tl-radius);
	background: var(--tl-surface-sunken, #f7f8f9);
}

/*
 * The sentence above the approve button. It is what stops "Approve" reading
 * like filing something, so it must not look like a caption.
 */
.lspms-proof__warn {
	margin: 0;
	max-width: var(--tl-measure, 70ch);
	padding: var(--tl-space-2) var(--tl-space-3);
	border-left: 3px solid var(--tl-warning, #b45309);
	background: var(--tl-surface, #fff);
	font-size: var(--tl-size-xs);
	line-height: 1.55;
}

/* A financial action does not look like an ordinary secondary control. */
.lspms .lspms-proof__approve,
.lshostel-app .lspms-proof__approve,
.lsgroup .lspms-proof__approve {
	font-weight: var(--tl-weight-semi, 600);
	padding-inline: var(--tl-space-4);
}

/*
 * The developer credit, at the foot of every management screen.
 *
 * Scoped to all three businesses because all three shells print it, and styled
 * to be the quietest thing on the page: a manager is here to run a business,
 * not to read about who built the software. Muted, small, and separated by a
 * hairline rather than by weight.
 */
.lspms .lspms-credit,
.lshostel-app .lspms-credit,
.lsgroup .lspms-credit {
	margin: var(--tl-space-6, 32px) 0 0;
	padding-top: var(--tl-space-3);
	border-top: 1px solid var(--tl-neutral-200);
	color: var(--tl-neutral-500);
	font-size: var(--tl-size-xs);
	text-align: right;
}

.lspms .lspms-credit a,
.lshostel-app .lspms-credit a,
.lsgroup .lspms-credit a {
	color: inherit;
	text-decoration: none;
	border-bottom: 1px solid var(--tl-neutral-300);
}

.lspms .lspms-credit a:hover,
.lspms .lspms-credit a:focus-visible,
.lshostel-app .lspms-credit a:hover,
.lshostel-app .lspms-credit a:focus-visible,
.lsgroup .lspms-credit a:hover,
.lsgroup .lspms-credit a:focus-visible {
	color: var(--tl-neutral-700);
	border-bottom-color: currentColor;
}

/*
 * The public payment instructions. The account, then what to do with it, then
 * the sentence that stops somebody thinking a sent receipt is a paid bill.
 */
.lspms .lspms-payinfo,
.lshostel-app .lspms-payinfo,
.lsgroup .lspms-payinfo {
	display: grid;
	gap: var(--tl-space-3);
	margin: 0 0 var(--tl-space-4);
	padding: var(--tl-space-4);
	border: 1px solid var(--tl-neutral-200);
	border-radius: var(--tl-radius);
	background: var(--tl-surface, #fff);
	max-width: 100%;
}

.lspms-payinfo__head {
	display: flex;
	flex-wrap: wrap;
	gap: var(--tl-space-2);
	align-items: center;
	justify-content: space-between;
	margin: 0;
}

.lspms-payinfo__kind {
	font-weight: var(--tl-weight-semi, 600);
}

/*
 * RECOMMENDED carries a mark as well as a colour, because it is a
 * recommendation and a reader who cannot see the green must still get it.
 */
.lspms-payinfo__flag {
	display: inline-flex;
	align-items: center;
	gap: 4px;
	padding: 2px var(--tl-space-2);
	border-radius: 999px;
	background: var(--tl-good, #15803d);
	color: #fff;
	font-size: var(--tl-size-xs);
	font-weight: var(--tl-weight-semi, 600);
	letter-spacing: 0.04em;
}

.lspms-payinfo__flag .dashicons {
	font-size: 14px;
	width: 14px;
	height: 14px;
}

.lspms-payinfo__steps {
	margin: 0;
	padding-inline-start: var(--tl-space-5);
	max-width: var(--tl-measure, 70ch);
	font-size: var(--tl-size-xs);
	line-height: 1.6;
}

.lspms-payinfo__steps li { margin: 0 0 4px; }

.lspms-payinfo__warn {
	display: flex;
	gap: var(--tl-space-2);
	align-items: flex-start;
	margin: 0;
	padding: var(--tl-space-3);
	border-left: 3px solid var(--tl-warning, #b45309);
	background: var(--tl-surface-sunken, #f7f8f9);
	font-size: var(--tl-size-xs);
	line-height: 1.55;
	max-width: var(--tl-measure, 70ch);
}

.lspms-payinfo__warn .dashicons {
	flex: 0 0 auto;
	font-size: 16px;
	width: 16px;
	height: 16px;
	color: var(--tl-warning, #b45309);
}

@media screen and (max-width: 600px) {
	/* Label above value: a 14rem label column is most of a phone. */
	.lspms-proof__detail-row { grid-template-columns: minmax(0, 1fr); gap: 2px; }
	.lspms-proof__filter--go { flex: 1 1 100%; }
}

/* ==================================================== staff invitations ====
 *
 * One screen for three businesses, so — like the payment-proof screen above —
 * the classes that carry layout are declared under all three scopes. A class
 * declared once under `.lspms` and emitted inside `.lshostel-app` renders on
 * browser defaults, which is how a filter bar became four full-width rows and
 * how the homepage hero became a 51-pixel strip.
 */

.lspms .lspms-invite,
.lshostel-app .lspms-invite,
.lsgroup .lspms-invite {
	margin: var(--tl-space-5) 0 0;
}

.lspms-invite__title {
	margin: 0 0 var(--tl-space-2);
	font-size: var(--tl-size-md, 1rem);
	font-weight: var(--tl-weight-semi, 600);
}

.lspms-invite__subtitle {
	margin: var(--tl-space-5) 0 var(--tl-space-2);
	font-size: var(--tl-size-sm, 0.9375rem);
	font-weight: var(--tl-weight-semi, 600);
}

.lspms-invite__lead,
.lspms-invite__none {
	margin: 0 0 var(--tl-space-4);
	color: var(--tl-ink-2, #4a5654);
	font-size: var(--tl-size-xs);
	line-height: 1.55;
	max-width: var(--tl-measure, 70ch);
}

/*
 * Four fields that must not become four full-width rows on a desktop and must
 * not become a two-column squeeze on a phone. auto-fit with a floor of 14rem
 * gives one across at 375px and two or more from a tablet up, with no media
 * query to keep in step with anything.
 */
.lspms .lspms-invite__grid,
.lshostel-app .lspms-invite__grid,
.lsgroup .lspms-invite__grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
	gap: var(--tl-space-3);
	margin: 0 0 var(--tl-space-3);
}

.lspms .lspms-invite__field,
.lshostel-app .lspms-invite__field,
.lsgroup .lspms-invite__field {
	display: grid;
	gap: 4px;
	margin: 0;
	min-width: 0;
}

.lspms-invite__field label {
	font-size: var(--tl-size-xs);
	font-weight: var(--tl-weight-semi, 600);
}

.lspms .lspms-invite__field input,
.lspms .lspms-invite__field select,
.lshostel-app .lspms-invite__field input,
.lshostel-app .lspms-invite__field select,
.lsgroup .lspms-invite__field input,
.lsgroup .lspms-invite__field select {
	width: 100%;
	max-width: 100%;
	min-width: 0;
	box-sizing: border-box;
}

.lspms .lspms-invite__submit,
.lshostel-app .lspms-invite__submit,
.lsgroup .lspms-invite__submit {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--tl-space-3);
	margin: 0;
}

.lspms-invite__hint {
	color: var(--tl-ink-3, #74807e);
	font-size: var(--tl-size-xs);
}

/* The table scrolls inside itself rather than widening the page on a phone. */
.lspms .lspms-invite__scroll,
.lshostel-app .lspms-invite__scroll,
.lsgroup .lspms-invite__scroll {
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
}

.lspms .lspms-invite__table,
.lshostel-app .lspms-invite__table,
.lsgroup .lspms-invite__table {
	width: 100%;
	border-collapse: collapse;
	font-size: var(--tl-size-xs);
}

.lspms-invite__table th,
.lspms-invite__table td {
	padding: var(--tl-space-2) var(--tl-space-3);
	border-bottom: 1px solid var(--tl-neutral-200);
	text-align: left;
	vertical-align: middle;
	white-space: nowrap;
}

/*
 * The state of an invitation, as a word rather than a colour alone: "Invited"
 * and "Expired" have to be distinguishable in a photocopy and to somebody who
 * does not see the difference between amber and grey.
 */
.lspms-invite__state {
	display: inline-block;
	padding: 2px 8px;
	border-radius: 999px;
	background: var(--tl-surface-sunken, #f7f8f9);
	font-size: var(--tl-size-xs, 0.75rem);
	font-weight: var(--tl-weight-semi, 600);
	white-space: nowrap;
}

.lspms-invite__state--pending  { background: #fdf3e3; color: #8a5a12; }
.lspms-invite__state--accepted { background: #e3f2ea; color: #146b45; }
.lspms-invite__state--revoked,
.lspms-invite__state--expired  { background: #f1f2f3; color: #5a625f; }

/* The cancel button sits in a table cell and must not stack its own row. */
.lspms .lspms-invite__inline,
.lshostel-app .lspms-invite__inline,
.lsgroup .lspms-invite__inline {
	display: inline;
	margin: 0;
}

.lspms .lspms-invite__form,
.lshostel-app .lspms-invite__form,
.lsgroup .lspms-invite__form {
	margin: 0;
}

/*
 * The link, shown once, only when the email did not go. Deliberately loud: it
 * is the one thing on this page that cannot be recovered by reloading.
 */
.lspms .lspms-invite__link,
.lshostel-app .lspms-invite__link,
.lsgroup .lspms-invite__link {
	margin: 0 0 var(--tl-space-4);
	padding: var(--tl-space-3);
	border-left: 3px solid var(--tl-warning, #b45309);
	background: var(--tl-surface-sunken, #f7f8f9);
}

.lspms-invite__linklead {
	margin: 0 0 var(--tl-space-2);
	font-size: var(--tl-size-xs);
	line-height: 1.55;
}

.lspms-invite__linkvalue {
	margin: 0;
	overflow-wrap: anywhere;
	word-break: break-all;
}

.lspms-invite__linkvalue code {
	font-size: var(--tl-size-xs);
	background: none;
	padding: 0;
}

/* ------------------------------------------------ permission exceptions ----
 *
 * A second row under a person, collapsed unless they have exceptions. Declared
 * under all three scopes for the same reason as everything else on this
 * screen: one file renders it into three different wrappers.
 */

/*
 * The row itself carries the sunken ground, so the panel reads as belonging to
 * the person above it rather than as another entry in the list. The cell inherits
 * it; giving only the cell a background left the row's own borders unpainted.
 */
.lspms .lspms-invite__permrow,
.lshostel-app .lspms-invite__permrow,
.lsgroup .lspms-invite__permrow {
	background: var(--tl-surface-sunken, #f7f8f9);
	border-bottom: 1px solid var(--tl-neutral-200);
}

.lspms .lspms-invite__permrow > td,
.lshostel-app .lspms-invite__permrow > td,
.lsgroup .lspms-invite__permrow > td {
	padding: 0 var(--tl-space-3) var(--tl-space-3);
	background: var(--tl-surface-sunken, #f7f8f9);
	white-space: normal;
}

/*
 * The disclosure. Block rather than inline so its summary and its contents take
 * the full width of the cell; a <details> left on browser defaults inside a
 * table cell collapses to the width of its summary text.
 */
.lspms .lspms-invite__perms,
.lshostel-app .lspms-invite__perms,
.lsgroup .lspms-invite__perms {
	display: block;
	max-width: var(--tl-measure-wide, 100%);
}

.lspms-invite__perms summary {
	cursor: pointer;
	padding: var(--tl-space-2) 0;
	font-size: var(--tl-size-xs);
	color: var(--tl-ink-2, #4a5654);
}

/*
 * Forty checkboxes that must not become forty full-width rows on a desktop and
 * must not become an unreadable two-column squeeze on a phone. auto-fit with a
 * floor of min(100%, 18rem) gives one column at 320px and three or four on a
 * desktop, and the min() stops the floor overflowing a container narrower than
 * itself.
 */
.lspms .lspms-invite__perms-grid,
.lshostel-app .lspms-invite__perms-grid,
.lsgroup .lspms-invite__perms-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
	gap: 4px var(--tl-space-3);
	margin: 0 0 var(--tl-space-3);
}

.lspms .lspms-invite__perm,
.lshostel-app .lspms-invite__perm,
.lsgroup .lspms-invite__perm {
	display: flex;
	align-items: flex-start;
	gap: 8px;
	min-width: 0;
	font-size: var(--tl-size-xs);
	line-height: 1.45;
}

.lspms-invite__perm input { flex: 0 0 auto; margin-top: 3px; }
.lspms-invite__perm span { min-width: 0; overflow-wrap: anywhere; }

/*
 * "added" / "removed" beside a permission that differs from the role. A word,
 * not a colour alone: the difference has to survive a photocopy and a reader
 * who does not see the difference between grey and amber.
 */
.lspms-invite__permnote {
	flex: 0 0 auto;
	padding: 0 6px;
	border-radius: 999px;
	background: #fdf3e3;
	color: #8a5a12;
	font-size: var(--tl-size-xs, 0.75rem);
	font-style: normal;
	font-weight: var(--tl-weight-semi, 600);
}

/* ==========================================================================
   A BUTTON THAT IS MID-REQUEST, IN ALL THREE APPLICATIONS
   ==========================================================================

   The guard that sets `is-busy` moved to toplife.js because it was never
   specific to the lodge (see the note there). Its appearance has to move with
   it: the hostel and the group now disable a button on submit, and without
   these rules the button would be inert while still looking pressable, which is
   worse than no guard at all.

   Scoped to the three application shells rather than written bare, so it cannot
   reach wp-admin's own buttons. The lodge keeps its own copy in pms.css; that
   one is more specific and wins, so nothing about the lodge changes.
   ========================================================================== */

.lshostel-app .button.is-busy,
.lsgroup .button.is-busy {
	opacity: 0.55;
	cursor: not-allowed;
	box-shadow: none;
}

.lshostel-app .button.is-busy::after,
.lsgroup .button.is-busy::after {
	content: "";
	display: inline-block;
	width: 12px;
	height: 12px;
	margin-inline-start: 6px;
	vertical-align: -1px;
	border-radius: 50%;
	border: 2px solid currentColor;
	border-right-color: transparent;
	animation: tl-busy-spin 0.6s linear infinite;
}

@keyframes tl-busy-spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
	.lshostel-app .button.is-busy::after,
	.lsgroup .button.is-busy::after {
		animation-duration: 0.01ms;
	}
}
