/* =========================================================================
   Privatily Mail — Roundcube child skin (extends Elastic)
   -------------------------------------------------------------------------
   LAYERING CONTRACT — read before editing.

   Elastic's template (templates/includes/layout.html) emits a single
       <link rel="stylesheet" href="/styles/styles.css">
   which Roundcube resolves through the skin chain, so once skin=privatily
   this file is loaded INSTEAD OF Elastic's styles.css.

   That resolution is NOT simply child-first, and the difference matters.
   rcmail_output_html.php sets $this->base_path to the skin directory where the
   TEMPLATE was found, then get_skin_file() array_unshift()s base_path to the
   FRONT of the search path. A child skin that ships no templates therefore
   loses every asset lookup to its parent: the page renders perfectly but
   styles.css, logo.svg and favicon.ico all resolve to elastic, and the
   branding silently does not apply.

   The fix lives in install.sh: skins/privatily/templates is a symlink to
   ../elastic/templates. The template then resolves inside skins/privatily,
   which puts us first for assets, while forking zero template files —
   Elastic's own templates are what get read, and template changes in an
   update flow through untouched. Do not delete that symlink.

   Therefore the @import below is load-bearing. It pulls in Elastic's own
   COMPILED stylesheet verbatim, at its live on-disk path. We never copy,
   fork, or recompile Elastic's LESS — a Roundcube update rebuilds
   elastic/styles/styles.css and we automatically pick up the new build on
   the next request. Everything after the @import is our layer on top.

   DO NOT remove the @import. DO NOT ship a styles.min.css in this skin
   (Roundcube's file_mod() prefers a .min sibling if one exists, which would
   silently bypass this file).

   Cascade note: because the @import is first, Elastic's rules are inserted
   ahead of ours, so our declarations win ties without !important. We use
   !important only where we must beat (a) Elastic's deeper compiled
   selectors and (b) the ispconfig3_* plugin stylesheets, which Roundcube
   injects as separate <link> tags AFTER this file.
   ========================================================================= */

@import url("../../elastic/styles/styles.css");

/* ---------- Inter, self-hosted (never hotlinked) ------------------------ */
/* One variable woff2 per subset covers weights 100–900.                    */

@font-face {
	font-family: 'Inter';
	font-style: normal;
	font-weight: 100 900;
	font-display: swap;
	src: url("../fonts/inter-latin.woff2") format('woff2');
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: 'Inter';
	font-style: normal;
	font-weight: 100 900;
	font-display: swap;
	src: url("../fonts/inter-latin-ext.woff2") format('woff2');
	unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------- Brand tokens ------------------------------------------------ */

:root {
	--pv-primary:        #4632DA;
	--pv-primary-600:    #3A29B8;   /* hover / pressed                      */
	--pv-primary-300:    #7B6BE8;   /* subtle borders, disabled primary     */
	--pv-primary-tint:   rgba(70, 50, 218, 0.09);   /* selection wash       */
	--pv-primary-tint-2: rgba(70, 50, 218, 0.16);   /* hover on selection   */

	--pv-accent:         #FFA74F;   /* flags / starred / attention          */
	--pv-cta:            #FE7B79;   /* coral — call to action               */
	--pv-cta-600:        #F26260;

	--pv-dark:           #171226;   /* dark-mode base surface               */
	--pv-dark-raised:    #211A33;   /* cards, list panes                    */
	--pv-dark-line:      #302748;   /* dark-mode borders                    */
	--pv-on-dark:        #E9E6F5;   /* dark-mode body text                  */
	--pv-primary-on-dark:#A99BF5;   /* purple is too dark to read on #171226 */

	--pv-gradient:       linear-gradient(135deg, #4632DA 0%, #1A2439 100%);

	--pv-ink:            #1A1626;   /* body text on light                   */
	--pv-muted:          #5B5B6B;   /* secondary text — 6.7:1 on white      */
	--pv-line:           #E2E0EC;

	/* Raised neutrals. These exist so that every surface Elastic or TinyMCE
	   paints with a stock grey — toolbars, chips, input-group addons, menus —
	   has ONE brand answer that is mode-aware, instead of a hand-written dark
	   twin per component. See the COMPOSE & TINYMCE section. */
	--pv-surface:        #F1EFF7;   /* raised: toolbars, chips, addons      */
	--pv-surface-2:      #E7E4F5;   /* hover on a raised surface            */
	--pv-panel:          #FFFFFF;   /* menus, dialogs, popovers             */
	--pv-control-line:   #8C85AB;   /* button boundary — 3.47:1 on white,
	                                   i.e. above the 3:1 floor of WCAG
	                                   1.4.11 for UI components            */

	--pv-radius:         10px;
	--pv-radius-sm:      6px;
	--pv-radius-lg:      16px;

	--pv-font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
	           'Helvetica Neue', Arial, sans-serif;

	--pv-focus: 0 0 0 3px rgba(70, 50, 218, 0.35);
}

/* The ink tokens are MODE-AWARE, so every rule that uses them adapts by
   construction instead of needing a hand-written dark twin.
   This closes a whole class of bug rather than an instance of it: an audit
   found 14 rules referencing --pv-ink / --pv-muted with no dark counterpart,
   which is why form labels on the ISPConfig plugin pages were rendering
   #5B5B6B on a dark surface — measured 2.5:1, a clear AA failure that no
   screenshot had happened to catch. Redefining the tokens here fixes all of
   them at once, and any rule added later inherits the same behaviour. */
html.dark-mode {
	--pv-ink:   #E9E6F5;
	--pv-muted: #A8A3BC;
	--pv-line:  #302748;

	--pv-surface:      #211A33;
	--pv-surface-2:    #2F2746;
	--pv-panel:        #211A33;
	--pv-control-line: #6E6595;   /* 3.44:1 on the #171226 base */
}

/* ---------- Typography -------------------------------------------------- */

html, body,
input, select, textarea, button,
.propform, .formcontent, .listing, .toolbar, .menu {
	font-family: var(--pv-font);
}

body {
	color: var(--pv-ink);
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

/* Elastic sets its own ink (#2c363a) explicitly on form controls and on the
   chrome, so `body { color }` never reached them. Dark mode already overrode
   all of it, which left the ink asymmetric BY MODE: ours below #171226, and
   Elastic's above it — measured on 24 elements in the compose view alone.
   The token is mode-aware, so this is the one place it needs saying. */
.form-control,
.custom-select,
select.form-control,
textarea.form-control,
input.form-control,
.menu.toolbar {
	color: var(--pv-ink);
}

/* The chrome needs !important: Elastic sets the ink through deeper selectors
   than `.header`, so the plain rule above never reached the toolbar or its
   button labels. Hover / selected keep their own colours further down. */
.header,
.header .header-title,
.header[role="toolbar"] a:not(.disabled),
#layout-content > .header a:not(.disabled),
#layout-list > .header a:not(.disabled),
#layout-sidebar > .header a:not(.disabled),
.header[role="toolbar"] a:not(.disabled) .inner,
#layout-content > .header a:not(.disabled) .inner,
#layout-list > .header a:not(.disabled) .inner,
#layout-sidebar > .header a:not(.disabled) .inner,
.header[role="toolbar"] a:not(.disabled):before,
#layout-content > .header a:not(.disabled):before,
#layout-list > .header a:not(.disabled):before,
#layout-sidebar > .header a:not(.disabled):before {
	color: var(--pv-ink) !important;
}

/* =========================================================================
   LOGIN PAGE
   -------------------------------------------------------------------------
   Elastic's markup, unforked:
     #layout-content.no-navbar > #logo + form#login-form > .input-group ...
   privatily_login.js moves #logo inside the form at runtime so the wordmark
   sits on the card, and appends #pv-login-bg for the animated backdrop.

   CONTRAST FLOOR — the reason the card is as opaque as it is.
   The shader clamps its output to #4D38E0, so the lightest pixel the
   animation can ever produce is a known colour. Every value below was
   composited against THAT, not against an average frame, so legibility never
   depends on what the animation is doing:

     card rgba(23,18,38,.76) over #4D38E0  ->  worst-case surface rgb(36,27,83)
       input text   #E9E6F5   12.61:1
       placeholder  #A8A3BC    6.36:1   <- this IS the visible label; ui.js
                                           hides the <label> and copies its
                                           text into the placeholder
       underline    white 45%  4.22:1   (UI component, needs 3:1)
       focus underline #A99BF5 6.41:1
       button       #fff on #4632DA 7.69:1

   Note the focus underline is the LIGHT purple. Brand #4632DA measures 2.01:1
   against the card and would have been invisible — the sort of thing that only
   shows up if you compute it.
   ========================================================================= */

/* ONE APPEARANCE, MODE-INDEPENDENT.
   -------------------------------------------------------------------------
   The card is glass over a fixed dark backdrop in BOTH modes: the shader, or
   the brand gradient on every fallback path. So there is no light version of
   this surface to design, and mode-aware tokens must not reach inside it.

   Pinning them on body.task-login fixes the whole class rather than each
   symptom. Custom properties inherit, and a declaration on <body> always beats
   one inherited from <html> — which is where html.dark-mode redefines them —
   so every rule inside the login page resolves to these values in both modes,
   including any rule added later that has no idea the login page exists. That
   is the property worth having: the two modes cannot drift apart again,
   because there is only one set of values to drift.

   Values are the DARK-side ones, because a dark backdrop is what they sit on.
   --pv-line and --pv-control-line become white alphas rather than the palette
   greys: on glass, a tint that lets the backdrop through reads as one surface,
   where an opaque grey reads as a panel stuck on top of it. */
body.task-login {
	--pv-ink:           #E9E6F5;
	--pv-muted:         #A8A3BC;
	--pv-line:          rgba(255, 255, 255, 0.14);
	--pv-surface:       rgba(255, 255, 255, 0.06);
	--pv-surface-2:     rgba(255, 255, 255, 0.10);
	--pv-panel:         #171226;
	--pv-control-line:  rgba(255, 255, 255, 0.45);
}

/* Base layer: the static brand gradient. This is what every fallback path
   lands on — reduced motion, no WebGL, context loss, or a frame rate too low
   to be worth it. The canvas simply paints over it when it runs. */
/* Layering, and why it is arranged this way.
   The gradient lives on <body>, NOT on #layout-content. Giving the content
   column its own z-index made it a stacking context, which trapped the card
   underneath the fixed canvas no matter how high the card's z-index went —
   the form simply vanished behind the artwork. Painting order is now:
     body background (static gradient, the fallback)
       -> #pv-login-bg   z-index 0   the shader, when it runs
         -> #layout-content z-index 1  the card, always on top */
body.task-login,
body.task-login #layout {
	background: var(--pv-gradient) !important;
	background-attachment: fixed !important;
}

body.task-login #layout,
#layout-content.no-navbar {
	background-color: transparent !important;
	background-image: none !important;
}

body.task-login #layout {
	background: var(--pv-gradient) !important;
}

#layout-content.no-navbar {
	position: relative;
	z-index: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	min-height: 100vh;
	/* dvh where supported: on mobile browsers with a retracting toolbar, 100vh
	   is the LARGE viewport, so the card is centred against a box taller than
	   what is actually on screen and sits low until the toolbar hides. */
	min-height: 100dvh;
	padding: 24px;
	background: transparent !important;
}

#pv-login-bg {
	position: fixed;
	inset: 0;
	width: 100%;
	height: 100%;
	display: block;
	z-index: 0;
	pointer-events: none;
	opacity: 0;                     /* the script raises this on first paint */
	transition: opacity .8s ease;
}

@media (prefers-reduced-motion: reduce) {
	#pv-login-bg { transition: none; }
}

/* ---- the glass card --------------------------------------------------- */
#login-form {
	position: relative;
	/* Elastic pushes the card down with `#login-form { top: 20vh }` — a
	   positioned OFFSET, not a layout one, so the flex centring above is
	   working correctly and then the card is shifted 20vh below where it was
	   placed. Measured 192.4px low on a 962px viewport, which is exactly 20vh.
	   position: relative stays because z-index needs it. */
	top: 0 !important;
	z-index: 2;
	width: 100%;
	max-width: 400px;
	padding: 40px 34px 34px !important;
	background: rgba(23, 18, 38, 0.76) !important;
	-webkit-backdrop-filter: blur(22px) saturate(140%);
	backdrop-filter: blur(22px) saturate(140%);
	border: 1px solid rgba(255, 255, 255, 0.14) !important;
	border-radius: 22px !important;
	box-shadow:
		0 24px 60px rgba(6, 4, 18, 0.55),
		0 2px 8px rgba(6, 4, 18, 0.35),
		inset 0 1px 0 rgba(255, 255, 255, 0.10) !important;
}

/* Browsers without backdrop-filter get more tint instead of blur, so the
   contrast floor still holds. */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
	#login-form { background: rgba(23, 18, 38, 0.90) !important; }
}

#login-form .box-inner {
	border-top: none !important;
	padding: 0 !important;
	background: transparent !important;
}

/* ---- wordmark, now a child of the form -------------------------------- */
/* Elastic pushes this down the page with `.task-login #logo { position:
   relative; top: 16vh }` — 149px at a 930px viewport — which is why the
   wordmark rendered on top of the fields once it moved inside the card.
   Reset the offset explicitly; it is not enough to restyle the box. */
#login-form #logo,
#layout-content.no-navbar #logo,
.task-login #logo {
	content: url("../images/logo-dark.svg");
	display: block;
	position: static !important;
	top: auto !important;
	width: 168px;
	max-width: 70%;
	max-height: none !important;
	height: auto;
	margin: 0 auto 30px !important;
	opacity: 1;
	filter: none;
}

/* ---- underline-only fields -------------------------------------------- */
/* Elastic's login form is a <table>; ui.js then puts `.input-group` on the
   <td> that holds the field. So the table, tbody and rows collapse to blocks
   for vertical stacking, but the field cell MUST stay flex — forcing it to
   block put the icon on its own line above the input and left the placeholder
   with nowhere to render. */
#login-form table,
#login-form tbody,
#login-form tr {
	display: block;
	width: 100%;
	background: transparent !important;
	border: 0 !important;
	padding: 0 !important;
}

#login-form td {
	background: transparent !important;
	border: 0 !important;
	padding: 0 !important;
}

#login-form td:not(.input-group) {
	display: block;
	width: 100%;
}

#login-form tr {
	margin-bottom: 22px;
}

/* One indicator, on the wrapper — same rule the rest of the skin follows. */
#login-form td.input-group,
#login-form .input-group {
	display: flex !important;
	align-items: center;
	width: 100%;
	background: transparent !important;
	border: 0 !important;
	border-bottom: 1px solid rgba(255, 255, 255, 0.45) !important;
	border-radius: 0 !important;
	transition: border-color .18s ease;
}

#login-form .input-group-prepend {
	display: flex;
	align-items: center;
	flex: 0 0 auto;
}

#login-form .input-group > input.form-control {
	flex: 1 1 auto;
	min-width: 0;
}

#login-form .input-group:focus-within {
	border-bottom-color: var(--pv-primary-on-dark) !important;
	box-shadow: 0 1px 0 0 var(--pv-primary-on-dark) !important;
}

#login-form .input-group-text,
#login-form .input-group-prepend .input-group-text {
	background: transparent !important;
	border: 0 !important;
	color: #A8A3BC !important;
	padding-left: 0 !important;
	font-size: 1rem;
	/* Same height as the input so the icon and the field are one row rather
	   than two boxes of 29px and 42px that merely happen to be centred on each
	   other. Elastic already gives this element display:flex/align-items:center,
	   so the glyph stays centred as the box grows. */
	height: 3rem;
	padding-top: 0 !important;
	padding-bottom: 0 !important;
	/* Symmetric inset. It was padding-left:0, which put the glyph hard against
	   the card's inner edge (measured: icon x=662 against an inner edge of
	   661) while carrying 14px on the right — so the icon read as pushed out
	   of the field rather than sitting in it. */
	padding-left: 14px !important;
	padding-right: 14px !important;
	/* All four corners match. Elastic rounds only the LEADING corners of a
	   group addon (measured [4.2px 0 0 4.2px]) because it expects a bordered,
	   filled addon butted against the field. Ours is neither, and a radius on
	   two corners of a four-corner box is a latent inconsistency: invisible
	   while the background is transparent, visible the moment anything gives
	   it a fill or a focus ring. */
	border-radius: 0 !important;
}

/* Elastic's own glyph for this field is a person (\f007). It is an EMAIL
   address, so it gets an envelope. ui.js builds the element as
   <i class="input-group-text icon user">, deriving `user` from the input's
   name (_user), so this selector holds as long as the field keeps that name.
   This rule existed before the login redesign and the redesign deleted it —
   it is restored here, and it is the only thing that redesign silently
   reverted (audited by diffing every login selector across e7836a7). */
#login-form .input-group .icon.user:before {
	content: "\f0e0" !important;
}

#login-form .input-group:focus-within .input-group-text {
	color: var(--pv-primary-on-dark) !important;
}

/* THE INPUT MUST NOT BE A NATIVE-APPEARANCE CONTROL, and the reason is not
   cosmetic tidiness.
   `background: transparent` was already set and the computed value really was
   rgba(0,0,0,0) — yet a hard-edged darker rectangle painted behind each field,
   offset from the icon's box. The cause is the card's backdrop-filter: with
   appearance:auto the field is a native control, and Chrome does not sample the
   blurred backdrop underneath it, so the card's blur was simply missing over
   exactly the input's box and the raw shader showed through. Proven by two
   experiments: removing the card's backdrop-filter removed the rectangle, and
   so did appearance:none with the backdrop-filter left in place.
   So this declaration is load-bearing for an underline-only design sitting on
   glass. Do not drop it. */
#login-form input.form-control,
#login-form input.form-control:focus,
#login-form input.form-control:focus-visible {
	-webkit-appearance: none;
	appearance: none;
	background: transparent !important;
	background-color: transparent !important;
	border: 0 !important;
	border-radius: 0 !important;
	box-shadow: none !important;
	outline: 0 !important;
	color: #E9E6F5 !important;
	height: 3rem;
	padding-left: 2px !important;
	font-size: 0.98rem;
	-webkit-text-fill-color: #E9E6F5;
}

#login-form input.form-control::placeholder { color: #A8A3BC !important; opacity: 1; }
#login-form input.form-control::-webkit-input-placeholder { color: #A8A3BC !important; }

/* Chrome's autofill repaints the field with its own yellow-white; hold the
   card's palette so the contrast floor survives a saved password. */
#login-form input.form-control:-webkit-autofill,
#login-form input.form-control:-webkit-autofill:focus {
	-webkit-text-fill-color: #E9E6F5 !important;
	-webkit-box-shadow: 0 0 0 1000px rgba(23, 18, 38, 0.01) inset !important;
	transition: background-color 9999s ease-in-out 0s;
}

#login-form label,
#login-form table td.title {
	color: #A8A3BC !important;
	font-size: 0.82rem;
	letter-spacing: .02em;
}

/* ---- primary button with the sliding arrow ---------------------------- */
#login-form .btn-primary,
#login-form button.btn.btn-primary,
#login-form #rcmloginsubmit {
	display: flex !important;
	align-items: center;
	justify-content: center;
	gap: 0.55em;
	width: 100% !important;
	margin-top: 30px;
	height: 3rem;
	background-color: var(--pv-primary) !important;
	border: 0 !important;
	border-radius: 10px !important;
	color: #fff !important;
	font-weight: 600;
	font-size: 0.95rem;
	letter-spacing: .04em;
	box-shadow: 0 8px 22px rgba(70, 50, 218, 0.42) !important;
	transition: background-color .18s ease, box-shadow .18s ease, transform .18s ease;
}

#login-form #rcmloginsubmit:after,
#login-form .btn-primary:after {
	content: "\2192";                 /* → */
	display: inline-block;
	font-size: 1.05em;
	line-height: 1;
	transform: translateX(0);
	transition: transform .22s cubic-bezier(.22,.61,.36,1);
}

#login-form #rcmloginsubmit:hover,
#login-form .btn-primary:hover,
#login-form #rcmloginsubmit:focus-visible {
	background-color: var(--pv-primary-600) !important;
	box-shadow: 0 10px 28px rgba(70, 50, 218, 0.55) !important;
	transform: translateY(-1px);
}

#login-form #rcmloginsubmit:hover:after,
#login-form .btn-primary:hover:after,
#login-form #rcmloginsubmit:focus-visible:after {
	transform: translateX(5px);
}

#login-form #rcmloginsubmit:focus-visible {
	outline: 2px solid var(--pv-primary-on-dark) !important;
	outline-offset: 3px;
}

#login-form #rcmloginsubmit:active { transform: translateY(0); }

/* ---- footer ----------------------------------------------------------- */
#login-footer,
#login-footer a {
	color: rgba(233, 230, 245, 0.72) !important;
	text-align: center;
	font-size: 0.78rem;
}

#login-footer { margin-top: 18px; }
#login-footer a:hover { color: #fff !important; }

/* Roundcube has no self-registration, no Google auth and no password reset,
   so there is deliberately nothing here for them — a dead link on a
   client-facing login page is worse than no link. */

/* ---- small screens ---------------------------------------------------- */
@media (max-width: 480px) {
	#layout-content.no-navbar { padding: 16px; }
	#login-form {
		padding: 32px 22px 26px !important;
		border-radius: 18px !important;
	}
	/* Needs to out-specify `#layout-content.no-navbar #logo` (2 IDs + a class)
	   in the base block, or the desktop width silently wins here. */
	#layout-content.no-navbar #login-form #logo,
	#login-form #logo {
		width: 148px !important;
		margin-bottom: 24px !important;
	}
}

/* ---- reduced motion: the canvas never starts, and nothing here moves --- */
@media (prefers-reduced-motion: reduce) {
	#login-form #rcmloginsubmit,
	#login-form #rcmloginsubmit:after,
	#login-form .input-group {
		transition: none !important;
	}
	#login-form #rcmloginsubmit:hover { transform: none; }
	#login-form #rcmloginsubmit:hover:after { transform: translateX(0); }
}

/* =========================================================================
   INTERFACE CHROME — task rail, toolbars, headers
   ========================================================================= */

#layout-menu,
#taskmenu,
#layout > .menu,
#taskmenu .special-buttons {
	background-color: var(--pv-primary) !important;
	background-image: none !important;
}

/* Ink only — never a background on the icon pseudo-element or the label span.
   Elastic wraps every rail label in <span class="inner">, so putting a
   background on the span paints a box behind the TEXT instead of washing the
   whole item (visible on "Dark mode", whose label is widest). */
/* :not(.compose) throughout — Compose is the one coral CTA in the rail, and
   these ID-specificity rules would otherwise beat the class-specificity
   compose rules further down and strip its background. */
#taskmenu a:not(.compose),
#taskmenu a:not(.compose):before,
#taskmenu a:not(.compose) span,
#taskmenu a:not(.compose) .inner,
#taskmenu .special-buttons a,
#taskmenu .special-buttons a:before,
#taskmenu .special-buttons a span {
	color: rgba(255, 255, 255, 0.88) !important;
	background-color: transparent !important;
	background-image: none !important;
}

/* Hover: one translucent white wash across the whole item, nothing else. */
/* Square, full-bleed: the wash spans the full rail width with no radius. */
#taskmenu a:not(.compose):hover,
#taskmenu a:not(.compose):focus,
#taskmenu .special-buttons a:hover,
#taskmenu .special-buttons a:focus {
	background-color: rgba(255, 255, 255, 0.12) !important;
	border-radius: 0 !important;
	margin-left: 0 !important;
	margin-right: 0 !important;
	width: 100% !important;
}

#taskmenu a:not(.compose):hover,
#taskmenu a:not(.compose):hover:before,
#taskmenu a:not(.compose):hover span,
#taskmenu a:not(.compose):focus,
#taskmenu a:not(.compose):focus:before,
#taskmenu a:not(.compose):focus span {
	color: #fff !important;
}

/* Active task reads by a SINGLE mechanism: a slightly stronger wash plus full
   white ink. No coral anywhere in the rail — coral is the CTA colour and it is
   already carrying Compose. Reusing it for a passive state is exactly the
   error the recovered sheet made with coral selection rows. */
#taskmenu a.selected,
#taskmenu .special-buttons a.selected {
	background-color: rgba(255, 255, 255, 0.20) !important;
	box-shadow: none !important;
	border: none !important;
	outline: none !important;
	border-radius: 0 !important;
	margin-left: 0 !important;
	margin-right: 0 !important;
	width: 100% !important;
}

/* Ink only. Deliberately does NOT list `#taskmenu a.selected` itself: it has
   the same specificity as the wash rule above and comes later, so including
   it here would reset the active item's background to transparent. */
#taskmenu a.selected:before,
#taskmenu a.selected span,
#taskmenu a.selected .inner {
	color: #fff !important;
	background-color: transparent !important;
}

#taskmenu a.selected {
	color: #fff !important;
}

#taskmenu a:focus-visible {
	outline: 2px solid #fff !important;
	outline-offset: -2px;
}

/* Mobile / popover menu header carries the wordmark on a white plate. */
#layout-menu > .popover-header,
#layout-menu .popover-header {
	background-color: #fff !important;
}

/* The rail is ~50px wide and the wordmark is 1000x380 (2.63:1), so the full
   lockup renders clipped there ("pri..."). The rail gets the icon-only mark
   (0.53:1, portrait); the login page keeps the wordmark, where there is width
   for it. Both are generated from the same artwork by tools/make-logo-icon.py. */
/* Elastic centres this header's contents with `line-height: 58px` plus
   `text-align: center`, which only works on inline boxes — our `display:block`
   image opted out of both and parked itself in the top-left. Make the header a
   flex box so the mark is centred on both axes regardless of its own display. */
#layout-menu .popover-header {
	display: flex !important;
	align-items: center !important;
	justify-content: center !important;
	height: 58px;
	padding: 0 !important;
}

#layout-menu .popover-header #logo {
	content: url("../images/logo-icon.svg");
	height: 36px;
	width: auto;
	max-width: 60px !important;   /* Elastic caps img at 35.1px; ours is portrait */
	max-height: 44px !important;
	margin: 0 !important;
	padding: 0 !important;
	display: block;
}

/* TOOLBARS — light, matching the message-list toolbar above them.
   Brand purple is the TASK RAIL ONLY. Every other surface (toolbars, lists,
   panes, forms) stays light, so the message toolbar is deliberately NOT
   painted here: Elastic's own neutral surface is what we want, and letting it
   through means the two toolbars match automatically across upgrades.
   Only the interactive states are brand-tinted.

   WHY EVERY TOOLBAR SELECTOR IS LISTED FOUR TIMES.
   These rules were scoped to `.header[role="toolbar"]` to keep them off the
   two other things a bare `.header` matches — `#message-header > .header` and
   `<td class="header from">` — which is what leaked purple onto message
   content earlier. But NOT EVERY TOOLBAR CARRIES THAT ROLE: the compose view's
   own toolbar is `#layout-content > div.header` with no role attribute at all,
   so Save / Attach / Signature / Responses had been falling through to
   Elastic's stock hover the entire time. Found by scanning for stock colours
   rather than by looking, because the stock hover is a pale grey that reads as
   "nothing happened" rather than as wrong.
   The structural selector — a direct child of a layout pane — is what actually
   distinguishes a toolbar from a message header, so it is used alongside the
   role, and both message-header cases stay excluded by construction. */
.header[role="toolbar"] a:not(.disabled):hover,
#layout-content > .header a:not(.disabled):hover,
#layout-list > .header a:not(.disabled):hover,
#layout-sidebar > .header a:not(.disabled):hover,
.header[role="toolbar"] a:not(.disabled):focus,
#layout-content > .header a:not(.disabled):focus,
#layout-list > .header a:not(.disabled):focus,
#layout-sidebar > .header a:not(.disabled):focus,
.header[role="toolbar"] a.selected,
#layout-content > .header a.selected,
#layout-list > .header a.selected,
#layout-sidebar > .header a.selected,
.header[role="toolbar"] button:not(:disabled):hover,
#layout-content > .header button:not(:disabled):hover,
#layout-list > .header button:not(:disabled):hover,
#layout-sidebar > .header button:not(:disabled):hover {
	background-color: var(--pv-primary-tint) !important;
	background-image: none !important;
	border-radius: var(--pv-radius-sm);
}

.header[role="toolbar"] a:not(.disabled):hover,
#layout-content > .header a:not(.disabled):hover,
#layout-list > .header a:not(.disabled):hover,
#layout-sidebar > .header a:not(.disabled):hover,
.header[role="toolbar"] a:not(.disabled):hover:before,
#layout-content > .header a:not(.disabled):hover:before,
#layout-list > .header a:not(.disabled):hover:before,
#layout-sidebar > .header a:not(.disabled):hover:before,
.header[role="toolbar"] a:not(.disabled):focus,
#layout-content > .header a:not(.disabled):focus,
#layout-list > .header a:not(.disabled):focus,
#layout-sidebar > .header a:not(.disabled):focus,
.header[role="toolbar"] a.selected,
#layout-content > .header a.selected,
#layout-list > .header a.selected,
#layout-sidebar > .header a.selected,
.header[role="toolbar"] a.selected:before,
#layout-content > .header a.selected:before,
#layout-list > .header a.selected:before,
#layout-sidebar > .header a.selected:before {
	color: var(--pv-primary) !important;
}

/* Labels never take a background of their own. */
.header[role="toolbar"] a span,
#layout-content > .header a span,
#layout-list > .header a span,
#layout-sidebar > .header a span,
.header[role="toolbar"] a .inner,
#layout-content > .header a .inner,
#layout-list > .header a .inner,
#layout-sidebar > .header a .inner {
	background-color: transparent !important;
}

/* Compose — the one true CTA. Coral with dark ink: white on #FE7B79 is
   2.5:1 and fails WCAG AA, dark ink on coral is 6.9:1 and passes. */
/* Compose lives in #taskmenu .action-buttons; the ID-level selector is needed
   to outrank the rail rules above. */
/* Colour applies to every Compose affordance... */
#taskmenu a.compose,
#taskmenu .action-buttons a.compose,
a.button.compose,
.toolbar a.compose,
.floating-action-buttons a.compose {
	background-color: var(--pv-cta) !important;
	color: var(--pv-dark) !important;
}

/* ...but the square, full-bleed shape is RAIL ONLY. The mobile
   floating-action button is a round floating control; forcing width:100% and
   radius 0 on it would turn it into a bar across the viewport. */
#taskmenu a.compose,
#taskmenu .action-buttons a.compose {
	border-radius: 0 !important;
	margin-left: 0 !important;
	margin-right: 0 !important;
	width: 100% !important;
}

#taskmenu a.compose:before,
#taskmenu a.compose span,
#taskmenu a.compose .inner,
a.button.compose:before,
.toolbar a.compose:before,
.floating-action-buttons a.compose:before,
a.button.compose span,
.toolbar a.compose span {
	color: var(--pv-dark) !important;
	background-color: transparent !important;
}

#taskmenu a.compose:hover,
#taskmenu a.compose:focus,
a.button.compose:hover,
.toolbar a.compose:hover,
.floating-action-buttons a.compose:hover {
	background-color: var(--pv-cta-600) !important;
}

/* Compose glyph: OUTLINE paper-plane, replacing Elastic's pencil-square
   (\f044) and pen (\f304 on the mobile FAB).

   Note on the codepoint: FontAwesome 4's outline variant was \f1d9
   ("paper-plane-o"), but Elastic ships FontAwesome 5, which dropped that
   codepoint. In FA5 the outline is the SAME \f1d8 rendered in the Regular
   face. Elastic declares 'Icons' twice — weight 900 = fa-solid-900,
   weight 400 = fa-regular-400 — and selects the outline elsewhere the same
   way (e.g. button.btn.delete:before). Using weight 400 here keeps Compose
   visually distinct from the Sent folder, which is \f1d8 at weight 900
   (solid), and needs no new font file. */
/* Filled (weight 900), matching Mail / Contacts / Settings beside it. This
   is the same glyph the Sent folder uses, but they sit in different columns
   at different sizes, so the repeat is acceptable — consistency within the
   rail matters more. */
#taskmenu a.compose:before,
.menu a.compose:before,
a.button.compose:before,
.floating-action-buttons a.button.compose:before {
	content: "\f1d8" !important;
	font-weight: 900 !important;
}

/* Compose opens a NEW message. In the compose view that sits next to the real
   Send button (label key "send"), and once the rail button is relabelled
   "Send" the two are indistinguishable — one sends the draft, the other
   discards focus and starts another. Elastic puts the action on <body>, so
   the rail button simply steps aside while composing. */
body.action-compose #taskmenu a.compose,
body.action-compose .floating-action-buttons a.button.compose {
	display: none !important;
}

/* =========================================================================
   LISTS & SELECTION
   Divergence from the recovered sheet: selection is PRIMARY-tinted, not
   solid coral. Coral is the CTA colour; using it for passive selection
   both over-signals and fails contrast at 2.5:1 with white text.
   ========================================================================= */

/* =========================================================================
   THE STATE SYSTEM — one definition, used by every list in the interface
   -------------------------------------------------------------------------
   Every stray-border report traced back to components inventing their own
   indicators. There is now exactly one vocabulary, and no component adds to it:

     AT REST    nothing. No border, no rail, no tint, no ring.
     HOVER      background wash only.
     SELECTED   stronger wash + ONE left rail + promoted text.
     FOCUS      :focus-visible only, and only on real controls (see below).

   THE RAIL IS A BORDER, NEVER A BOX-SHADOW. Elastic already reserves
   `border-left: 2px` on `.listing li > a` and on `td:first-child`; drawing our
   rail as an inset box-shadow put a second indicator right beside Elastic's
   border, which is the doubled left border seen in the Settings submenu. One
   property means one indicator, and reserving the width at rest means selecting
   a row shifts nothing.

   THE TINT VALUES ARE MEASURED, NOT CHOSEN BY EYE. Dark selection could not
   simply be deepened: at 28% the muted text drops to 4.42:1 and fails AA. So
   selected rows also promote their text to the primary ink, which removes the
   limiting factor and allows a 30% wash. Resulting contrast, composited
   against the real backgrounds:

     light  hover 1.10:1 vs rest · selected 1.31:1 · worst text 6.05:1
     dark   hover 1.17:1 vs rest · selected 1.78:1 · worst text 6.38:1
     rails  5.87:1 (light) · 4.24:1 (dark) against the surface they sit on
   ========================================================================= */

/* --- 1. AT REST: clear every indicator any layer might draw ------------- */
.listing li,
.listing li > a,
.listing li > div > a,
.listing tr,
.listing tr > td,
.messagelist tr > td,
#sections-table tr > td,
#mailboxlist li > a,
.treelist li > a,
html:not(.touch) .listing li > a,
html:not(.touch) .listing tbody tr > td:first-child,
html:not(.touch) .listing.focus tbody tr.focused > td:first-child {
	box-shadow: none !important;
	outline: 0 !important;
}

/* Reserve the rail on every row so selection never shifts layout.
   Elastic draws its own rail on THREE different targets depending on whether
   the list is in selection mode — `li > a`, `tbody tr > td:first-child`, and
   `:not(.withselection) tbody tr > td.selection + td` — each with a :focus /
   .focused variant that paints #9ddfff. Missing the third one is what kept
   putting a pale blue line on the first (auto-focused) message row and beside
   the selected Settings item. All three are reserved and cleared here. */
.listing li > a,
.listing tbody tr > td:first-child,
.listing:not(.withselection) tbody tr > td.selection + td,
.messagelist tbody tr > td:first-child,
#sections-table tr > td:first-child,
#mailboxlist li > a,
.treelist li > a,
html:not(.touch) .listing li > a,
html:not(.touch) .listing tbody tr > td:first-child,
html:not(.touch) .listing:not(.withselection) tbody tr > td.selection + td {
	border-left: 3px solid transparent !important;
}

/* Elastic's .focused rail (#9ddfff) is cleared only on rows that are NOT
   selected. Including selected rows here made this rule out-specify the rail
   below — measured as "selected row, 0 rails" in light mode, because the
   selected row is normally also the focused one. */
html:not(.touch) .listing li:not(.selected) > a:focus,
html:not(.touch) .listing.focus tbody tr.focused:not(.selected) > td:first-child,
html:not(.touch) .listing.focus:not(.withselection) tbody tr.focused:not(.selected) > td.selection + td {
	border-left-color: transparent !important;
}

/* --- 2. HOVER: a wash, nothing structural ------------------------------- */
.listing li:not(.selected) > a:hover,
.listing tr:not(.selected):hover > td,
.messagelist tr:not(.selected):hover > td,
#sections-table tr:not(.selected):hover > td,
#mailboxlist li:not(.selected) > a:hover,
.treelist li:not(.selected) > a:hover {
	background-color: rgba(70, 50, 218, 0.06) !important;
}

/* --- 3. SELECTED: wash + one rail + promoted text -----------------------
   The wash goes on the PAINTING element only — the <a> for li-lists, the <td>
   for tables. Putting it on the row as well composited the alpha twice, so the
   surface measured darker than designed (1.67:1 instead of 1.31:1) and no
   longer matched the contrast figures it was chosen from. */
.listing li.selected > a,
.listing li.selected > div > a,
.listing tr.selected > td,
.messagelist tr.selected > td,
.treelist li.selected > a,
#mailboxlist li.selected > a,
#sections-table tr.selected > td {
	background-color: rgba(70, 50, 218, 0.16) !important;
}

.listing li.selected,
.listing tr.selected,
#mailboxlist li.selected,
#sections-table tr.selected {
	background-color: transparent !important;
}

/* The rail selectors must out-specify the reserve block above, which carries
   Elastic's own `html:not(.touch) … tbody` prefix. Without matching that
   prefix the reserve wins and the rail silently never paints — measured as
   "selected row, 0 rails" in the message list. */
html:not(.touch) .listing li.selected > a,
html:not(.touch) .listing tbody tr.selected > td:first-child,
html:not(.touch) .listing:not(.withselection) tbody tr.selected > td.selection + td,
html:not(.touch) .messagelist tbody tr.selected > td:first-child,
#sections-table tr.selected > td:first-child,
#mailboxlist li.selected > a,
.treelist li.selected > a {
	border-left-color: var(--pv-primary) !important;
}

/* Promoted ink — everything on a selected row reads at full strength, which
   is what lets the wash be strong enough to be unmistakable. The unread badge
   keeps its own white-on-purple treatment. */
.listing li.selected,
.listing li.selected > a,
.listing li.selected a,
.listing li.selected span:not(.unreadcount),
.listing tr.selected > td,
.listing tr.selected td a,
.listing tr.selected td span:not(.unreadcount),
.messagelist tr.selected > td,
.messagelist tr.selected td a,
.messagelist tr.selected td span:not(.unreadcount),
#mailboxlist li.selected > a,
#mailboxlist li.selected > a span:not(.unreadcount),
#sections-table tr.selected > td,
#sections-table tr.selected td a {
	color: var(--pv-ink) !important;
}

/* Unread badge. Elastic paints these with its stock accent
   (.folderlist li.mailbox .unreadcount { background: #37beff }), and our
   selected-row ink rule was additionally darkening the digits — dark text on a
   dark purple disc. White on brand purple, everywhere the badge appears. */
.listing .unreadcount,
#mailboxlist .unreadcount,
.folderlist li.mailbox .unreadcount,
.folderlist li.mailbox.recent > a > .unreadcount,
.listing li.selected .unreadcount,
.listing li.focused .unreadcount,
#mailboxlist li.selected > a .unreadcount,
.badge {
	background-color: var(--pv-primary) !important;
	background-image: none !important;
	color: #fff !important;
	border-radius: 999px !important;
	padding: 2px 7px !important;
	font-weight: 600;
	font-size: .74rem;
}

/* On the purple rail a purple badge would vanish — invert it there. */
#taskmenu .unreadcount,
#taskmenu a .unreadcount {
	background-color: #fff !important;
	color: var(--pv-primary) !important;
}

html.dark-mode #taskmenu .unreadcount,
html.dark-mode #taskmenu a .unreadcount {
	background-color: var(--pv-primary-on-dark) !important;
	color: var(--pv-dark) !important;
}

.listing li.unread > a,
.listing tr.unread td,
.listing tr.unread td.subject {
	font-weight: 600;
}

/* Flagged / starred — the amber accent's job. */
.listing .flag span.flagged:before,
.listing td.flag span.flagged:before,
.messagelist .flagged td,
span.flagged:before {
	color: var(--pv-accent) !important;
}

/* Contact avatars: the recovered sheet hid these outright, which removes a
   real affordance. Keep them, brand the placeholder instead. */
.contactphoto,
#message-header .contactphoto {
	background-color: var(--pv-primary-tint) !important;
	border-radius: 50% !important;
	overflow: hidden;
}

.contactphoto img[src*="contactpic"] {
	opacity: .5;
	filter: grayscale(1);
}

/* --- 5. ROWS ARE SQUARE; THE CONTAINER DOES THE CLIPPING -----------------
   Rows in the panes were already square, but a list inside a popover was not:
   Elastic rounds the first and last row itself
       .popover .listing li:first-child { border-radius: .25rem .25rem 0 0 }
   to follow ITS popover radius of 0.25rem. Ours is 10px, so the two curves
   disagreed and the hover/selected wash on the top folder in the "Move to…"
   list rendered with a 3.5px corner inside a 10px one — the rounded row in an
   otherwise square list.

   The rule, not the patch: a row never carries a radius. The panel clips.
   .popover-body already has `overflow: hidden`, so giving it the panel's own
   radius makes the first and last row follow the panel exactly, whatever that
   radius later becomes. */
.popover .listing li:first-child,
.popover .listing li:last-child,
.popover .listing ul > li:first-child,
.popover .listing ul > li:last-child,
.popupmenu .listing li:first-child,
.popupmenu .listing li:last-child {
	border-radius: 0 !important;
}

.popover > .popover-body,
.popupmenu > .popover-body {
	border-radius: var(--pv-radius);
	overflow: hidden auto;
}

/* =========================================================================
   BUTTONS, LINKS, FOCUS
   ========================================================================= */

a,
.propform a,
a.button.icon.link {
	color: var(--pv-primary);
}

a:hover {
	color: var(--pv-primary-600);
}

.btn-primary,
a.btn-primary,
button.btn-primary,
input.btn-primary,
.formbuttons .btn.btn-primary,
.btn.btn-primary.submit {
	background-color: var(--pv-primary) !important;
	border-color: var(--pv-primary) !important;
	color: #fff !important;
	border-radius: var(--pv-radius-sm) !important;
	font-weight: 600;
}

.btn-primary:hover,
a.btn-primary:hover,
button.btn-primary:hover,
.formbuttons .btn.btn-primary:hover {
	background-color: var(--pv-primary-600) !important;
	border-color: var(--pv-primary-600) !important;
}

/* Secondary buttons — "Attach a file", dialog Cancel, and every .btn-secondary
   in the interface. This had a dark-mode rule and NO light-mode rule, so light
   fell through to Elastic's stock #8b9fa7 with white text: MEASURED 2.76:1,
   a clear AA failure that had been on the compose page the whole time. The
   tokens are mode-aware, so one definition now covers both halves.
       light  ink #1A1626 on #F1EFF7 = 15.53:1, boundary 3.47:1 on white
       dark   ink #E9E6F5 on #211A33 = 13.57:1, boundary 3.44:1 on #171226
   The boundary matters here because the fill is a near-page-colour neutral:
   without a 3:1 edge the control is not identifiable (WCAG 1.4.11). */
.btn-secondary,
.btn.btn-secondary,
button.btn-secondary,
a.btn-secondary {
	background-color: var(--pv-surface) !important;
	background-image: none !important;
	border-color: var(--pv-control-line) !important;
	color: var(--pv-ink) !important;
	border-radius: var(--pv-radius-sm) !important;
}

.btn-secondary:hover:not(:disabled),
.btn.btn-secondary:hover:not(:disabled) {
	background-color: var(--pv-surface-2) !important;
	border-color: var(--pv-control-line) !important;
	color: var(--pv-ink) !important;
}

.btn-secondary:before,
.btn.btn-secondary:before {
	color: inherit !important;
}

.btn,
button,
input[type="submit"],
input[type="button"] {
	border-radius: var(--pv-radius-sm);
}

/* --- FORM CONTROL BOUNDARIES --------------------------------------------
   For a text field on a plain page the border IS the control: nothing else
   says where it starts or that it can be typed into. Both modes were below the
   3:1 floor WCAG 1.4.11 sets for exactly that, and neither was a near miss:

       light   Elastic #ced4da on #ffffff      1.49:1
       dark    our     #302748 on #171226      1.31:1

   The dark figure is the one that mattered in use — at 1.31:1 the field edge is
   effectively invisible, so a form reads as floating labels with nothing to
   type into. That is a usability problem before it is a compliance one.

   ONE RULE, NO MODE PREFIX. --pv-control-line is already the token for "the
   edge of an interactive control" (it draws the secondary button and the
   attachment drop zone) and it is mode-aware, so a single declaration covers
   both halves and cannot drift apart later:

       light   #8C85AB   3.47:1 on white   ·  3.04:1 on the raised surface
       dark    #6E6595   3.44:1 on #171226 ·  3.14:1 on the raised surface

   Specificity is deliberately minimal (0,1,0) so every state rule below —
   focus, invalid, disabled — still wins without needing to be rewritten. */
.form-control,
.custom-select,
.custom-file-label,
.recipient-input,
.tagedit-list,
.multi-input > .content,
div.tox.tox-tinymce,
div.tox .tox-textfield,
div.tox .tox-textarea,
div.tox .tox-listboxfield .tox-listbox--select,
div.tox .tox-selectfield select,
div.tox .tox-color-input > input {
	border-color: var(--pv-control-line) !important;
}

/* Checkbox, radio and switch tracks are controls too, and Bootstrap's #adb5bd
   measures 2.40:1 on white. The CHECKED state is brand purple and already
   passes, so only the unchecked track needs this. */
.custom-control-label::before,
.custom-control-input:not(:checked) ~ .custom-control-label::before {
	border-color: var(--pv-control-line) !important;
}

/* Disabled controls keep a weaker edge on purpose: 1.4.11 exempts them, and a
   full-strength boundary on something you cannot use is a false affordance. */
.form-control:disabled,
.form-control[readonly],
.custom-select:disabled,
.custom-control-input:disabled ~ .custom-control-label::before {
	border-color: var(--pv-line) !important;
}

/* --- 4. FOCUS: :focus-visible only, one treatment, never doubled --------
   Two rules, mutually exclusive by element type:
     (a) form fields already have a border -> recolour it + add a ring shadow
     (b) everything else                   -> an outline
   Nothing gets both. List rows get neither: Roundcube puts tabindex="0" on
   them and focuses one programmatically on load, and Chrome grants
   :focus-visible to a programmatic focus() when there has been no prior
   pointer interaction — i.e. exactly on page load. That produced the stray
   ring on the first message row and the first Settings option. Selection is
   the affordance for rows, and arrow-key navigation moves it. */
a:focus-visible,
button:focus-visible,
select:focus-visible,
.btn:focus-visible,
[role="button"]:focus-visible {
	outline: 2px solid var(--pv-primary) !important;
	outline-offset: 2px;
	border-radius: var(--pv-radius-sm);
}

/* (a) Form fields: the border IS the ring. No outline, so nothing can double. */
input.form-control:focus-visible,
textarea.form-control:focus-visible,
select.form-control:focus-visible,
.recipient-input.focus,
.multi-input > .content.focused {
	border-color: var(--pv-primary) !important;
	box-shadow: 0 0 0 3px rgba(70, 50, 218, 0.28) !important;
	outline: 0 !important;
}

/* Rows and their cells: never a ring, in any focus flavour. */
.listing td:focus, .listing td:focus-visible,
.listing tr:focus, .listing tr:focus-visible,
.listing li:focus, .listing li:focus-visible,
.listing li > a:focus, .listing li > a:focus-visible,
#sections-table td:focus, #sections-table td:focus-visible,
#mailboxlist li > a:focus, #mailboxlist li > a:focus-visible,
.messagelist td:focus, .messagelist td:focus-visible {
	outline: 0 !important;
	box-shadow: none !important;
}

/* Composite widgets draw ONE ring, on the outer container. Their inner inputs
   must stay bare or the field renders a ring inside a ring — which is what the
   compose "To" field was doing. */
.recipient-input input:focus,
.recipient-input input:focus-visible,
.tagedit-list input:focus,
.tagedit-list input:focus-visible,
.multi-input input:focus,
.multi-input input:focus-visible,
.input-group-text input:focus,
.input-group-text input:focus-visible,
.searchbar input:focus,
.searchbar input:focus-visible {
	outline: 0 !important;
	box-shadow: none !important;
	border-color: transparent !important;
}

/* The search bar clips its children (`overflow: hidden`, height 36px), so a
   ring on the inner input had its top and bottom cut off and rendered as two
   stray edges down the left and right. The treatment belongs on the bar. */
.searchbar:focus-within {
	box-shadow: inset 0 0 0 2px var(--pv-primary) !important;
	border-radius: var(--pv-radius-sm);
}

html.dark-mode .searchbar:focus-within {
	box-shadow: inset 0 0 0 2px var(--pv-primary-on-dark) !important;
}

/* (form-field focus is defined once, in the state system above) */

input[type="checkbox"]:checked + .custom-control-indicator,
.custom-control-input:checked ~ .custom-control-indicator,
.custom-switch .custom-control-input:checked ~ .custom-control-label:before {
	background-color: var(--pv-primary) !important;
	border-color: var(--pv-primary) !important;
}

/* Cards, dialogs, popovers */
.popupmenu,
.popover,
.ui-dialog,
.ui-dialog .ui-dialog-content,
.formcontent,
#messagecontframe {
	border-radius: var(--pv-radius);
}

.ui-dialog .ui-dialog-titlebar {
	background: var(--pv-primary) !important;
	color: #fff !important;
	border-radius: var(--pv-radius) var(--pv-radius) 0 0;
}

.ui-dialog .ui-dialog-titlebar .ui-dialog-title {
	color: #fff !important;
}

/* MESSAGE HEADER — content, never chrome.
   Elastic's structure (templates/message.html):
     #message-header > .subject                 subject line
     #message-header > .header                  contact photo + content
         .header-summary > span                 "From X on <date>"
         .header-headers  td.header-title       labels (From, Date)
                          td.header.from|to|cc  sender / recipients
                          td.header.date        the date
         .header-links a                        Details, Plain text, headers
   This block sits on a light surface with near-black sender and muted date.
   The recovered sheet put this text at #999 on white (2.8:1, fails AA);
   ours is #5B5B6B at 6.7:1. */
#message-header,
#message-header > .header,
#message-header .header-content,
#message-header .header-summary,
#message-header .header-headers,
#message-header .header-headers td,
#message-header .header-links,
.message-partheaders,
.message-headerbox {
	background-color: #fff !important;
	background-image: none !important;
	border-color: var(--pv-line) !important;
}

#message-header > .subject,
#message-header .header-summary,
#message-header .header-summary > span,
#message-header .header-headers td.header.from,
#message-header .header-headers td.header.to,
#message-header .header-headers td.header.cc {
	color: var(--pv-ink) !important;
}

#message-header .header-headers td.header-title,
#message-header .header-headers td.header.date,
#message-header .header-summary .text-nowrap,
.message-partheaders .header-title {
	color: var(--pv-muted) !important;
}

#message-header a,
#message-header .header-links a,
#message-header .header-links a:before,
#message-header .header-summary a,
.message-partheaders a {
	color: var(--pv-primary) !important;
	background-color: transparent !important;
}

.message-subject,
h2.subject,
#message-header > .subject,
#message-header > .subject span.inner {
	color: var(--pv-ink) !important;
	font-weight: 600;
}

/* =========================================================================
   DARK MODE
   Elastic ships dark mode (meta.json: dark_mode_support) and we inherit it.
   DECISION: branded, not disabled — surfaces move to the #171226 token
   rather than the recovered sheet's pure #000.
   ========================================================================= */

html.dark-mode,
html.dark-mode body,
html.dark-mode #layout,
html.dark-mode #messagecontframe {
	background-color: var(--pv-dark) !important;
	color: var(--pv-on-dark) !important;
}

/* ONE deep base for every pane.
   Elastic's dark palette is a set of blue-greys an order of magnitude lighter
   than ours — #374549 (22 uses, luminance 0.056), #21292c (11 uses, 0.021),
   #2c373b, #374449 — against our base #171226 at 0.008. Left alone, the folder
   list and message list rendered at 0.013–0.056 while the rail sat at 0.005,
   so the middle columns read as light grey pretending to be dark. Panes now
   share the base and are separated by thin borders, not luminance steps. */
html.dark-mode #layout-sidebar,
html.dark-mode #layout-list,
/* :not(.task-login) because on the login page #layout-content is not a pane —
   it is the full-bleed backdrop the shader canvas and the card sit in. Painting
   it opaque there covered the static gradient on every fallback path (no WebGL,
   reduced motion, context lost), which is precisely when the gradient is the
   only backdrop there is. */
html.dark-mode body:not(.task-login) #layout-content,
html.dark-mode .mailbox-list,
html.dark-mode #mailboxlist-container,
html.dark-mode #messagelist-header,
html.dark-mode .listbox,
html.dark-mode .formcontent,
html.dark-mode .content,
html.dark-mode .scroller,
html.dark-mode .footer,
html.dark-mode #messagelist,
html.dark-mode .listing,
html.dark-mode .listing tbody td,
html.dark-mode .listing li,
html.dark-mode table.listing {
	background-color: var(--pv-dark) !important;
	background-image: none !important;
}

/* Separation by border, not brightness. */
html.dark-mode #layout-sidebar,
html.dark-mode #layout-list {
	border-right: 1px solid var(--pv-dark-line) !important;
}

html.dark-mode .listing tbody td,
html.dark-mode .listing li,
html.dark-mode ul.listing li ul {
	border-bottom-color: var(--pv-dark-line) !important;
	border-top-color: var(--pv-dark-line) !important;
}

/* Anything Elastic paints with its raised blue-grey becomes our raised tone,
   a small step above the base rather than a jump. */
html.dark-mode .popupmenu,
html.dark-mode .popover,
html.dark-mode .ui-dialog,
html.dark-mode .ui-widget-content,
html.dark-mode .menu.toolbar,
html.dark-mode .table-widget,
html.dark-mode .recipient-input li.recipient,
html.dark-mode .tagedit-list li.tagedit-listelement-old,
html.dark-mode .attachmentslist li,
html.dark-mode .boxtitle,
html.dark-mode .propform tbody td,
html.dark-mode fieldset legend {
	background-color: var(--pv-dark-raised) !important;
	border-color: var(--pv-dark-line) !important;
}

/* Form controls sit on the base with a visible edge — Elastic tinted the
   focused recipient field #2c373b (a teal-grey), which is what made the
   compose "To" box look like a different product.
   The EDGE colour is not set here any more: it comes from the one control-
   boundary rule in the FORM CONTROL BOUNDARIES section, so both modes move
   together. It used to be --pv-dark-line, which measured 1.31:1. */
html.dark-mode .form-control,
html.dark-mode .recipient-input,
html.dark-mode .recipient-input.focus,
html.dark-mode .multi-input > .content,
html.dark-mode .custom-select,
html.dark-mode .custom-file-label,
html.dark-mode .custom-file-label:focus {
	background-color: var(--pv-dark) !important;
	color: var(--pv-on-dark) !important;
}

html.dark-mode .recipient-input.focus,
html.dark-mode .multi-input > .content.focused {
	border-color: var(--pv-primary-on-dark) !important;
	box-shadow: 0 0 0 0.2rem rgba(169, 155, 245, 0.25) !important;
}

/* .btn-secondary used to be defined here, dark-mode only. It now lives in the
   BUTTONS section as a single mode-aware definition — see the note there; the
   missing light half was a measured 2.76:1 AA failure. */

/* Scrollbars were the lightest things on screen. */
html.dark-mode:not(.touch) ::-webkit-scrollbar-track {
	background-color: var(--pv-dark) !important;
}

html.dark-mode:not(.touch) ::-webkit-scrollbar-thumb {
	background-color: #3A3057 !important;
}

/* Last of Elastic's dark blue-greys, found by scanning every rendered element
   for its palette rather than by eye: #4d6066 was still drawing pane dividers,
   the search bar edge and the quota widget, and #8ba3a7 was colouring sender
   and address text. All mapped onto our tokens. */
html.dark-mode .searchbar,
html.dark-mode .header,
html.dark-mode .footer,
html.dark-mode .pagenav,
html.dark-mode #layout-list > .header,
html.dark-mode #layout-sidebar > .header {
	border-color: var(--pv-dark-line) !important;
}

html.dark-mode .quota-widget,
html.dark-mode .quota-widget .bar,
html.dark-mode span.bar {
	background-color: var(--pv-dark-raised) !important;
	border-color: var(--pv-dark-line) !important;
}

html.dark-mode .fromto,
html.dark-mode .adr,
html.dark-mode .rcmContactAddress,
html.dark-mode .messagelist td.fromto span,
html.dark-mode .messagelist span.date,
html.dark-mode .listing span.date,
html.dark-mode .contacts-table td.name {
	color: var(--pv-muted) !important;
}

html.dark-mode #layout-menu {
	border-right-color: var(--pv-dark-line) !important;
}

html.dark-mode #taskmenu,
html.dark-mode #layout > .menu,
html.dark-mode #layout-menu {
	background-color: #100C1C !important;
}

/* No background here on purpose. The message toolbar must match the message-
   list toolbar above it, and Elastic already gives both the same surface in
   each mode (#f4f4f4 in light, the pane colour in dark). Setting our own
   raised colour made them diverge in dark mode only. Border and interactive
   states are ours; the surface is Elastic's. */
html.dark-mode .header[role="toolbar"],
html.dark-mode #layout-content > .header,
html.dark-mode #layout-list > .header,
html.dark-mode #layout-sidebar > .header {
	border-color: var(--pv-dark-line) !important;
}

html.dark-mode .header[role="toolbar"] a:not(.disabled):hover,
html.dark-mode #layout-content > .header a:not(.disabled):hover,
html.dark-mode #layout-list > .header a:not(.disabled):hover,
html.dark-mode #layout-sidebar > .header a:not(.disabled):hover,
html.dark-mode .header[role="toolbar"] a:not(.disabled):focus,
html.dark-mode #layout-content > .header a:not(.disabled):focus,
html.dark-mode #layout-list > .header a:not(.disabled):focus,
html.dark-mode #layout-sidebar > .header a:not(.disabled):focus,
html.dark-mode .header[role="toolbar"] a.selected,
html.dark-mode #layout-content > .header a.selected,
html.dark-mode #layout-list > .header a.selected,
html.dark-mode #layout-sidebar > .header a.selected {
	background-color: rgba(169, 155, 245, 0.16) !important;
	color: var(--pv-primary-on-dark) !important;
}

/* #4632DA on #171226 is 2.4:1 — unreadable. Lighten purple in dark mode. */
html.dark-mode a,
html.dark-mode #message-header a,
html.dark-mode .propform a {
	color: var(--pv-primary-on-dark) !important;
}

/* --- the same three states, dark half ----------------------------------
   Selection is 30% here, not 16%: at 16% it measured 1.31:1 against the base
   and was barely distinguishable. 30% gives 1.78:1, and the promoted ink keeps
   text at 8.35:1 — deepening the wash alone would have dropped muted text to
   4.42:1 and failed AA, which is why the ink is promoted rather than the
   colour pushed further. */
html.dark-mode .listing li:not(.selected) > a:hover,
html.dark-mode .listing tr:not(.selected):hover > td,
html.dark-mode .messagelist tr:not(.selected):hover > td,
html.dark-mode #sections-table tr:not(.selected):hover > td,
html.dark-mode #mailboxlist li:not(.selected) > a:hover,
html.dark-mode .treelist li:not(.selected) > a:hover {
	background-color: rgba(169, 155, 245, 0.10) !important;
}

html.dark-mode .listing li.selected > a,
html.dark-mode .listing li.selected > div > a,
html.dark-mode .listing tr.selected > td,
html.dark-mode .messagelist tr.selected > td,
html.dark-mode .treelist li.selected > a,
html.dark-mode #mailboxlist li.selected > a,
html.dark-mode #sections-table tr.selected > td {
	background-color: rgba(169, 155, 245, 0.30) !important;
}

html.dark-mode .listing li.selected,
html.dark-mode .listing tr.selected,
html.dark-mode #mailboxlist li.selected,
html.dark-mode #sections-table tr.selected {
	background-color: transparent !important;
}

html.dark-mode .listing li.selected,
html.dark-mode .listing li.selected > a,
html.dark-mode .listing li.selected a,
html.dark-mode .listing li.selected span:not(.unreadcount),
html.dark-mode .listing tr.selected > td,
html.dark-mode .listing tr.selected td a,
html.dark-mode .listing tr.selected td span:not(.unreadcount),
html.dark-mode .messagelist tr.selected > td,
html.dark-mode .messagelist tr.selected td a,
html.dark-mode .messagelist tr.selected td span:not(.unreadcount),
html.dark-mode #mailboxlist li.selected > a,
html.dark-mode #mailboxlist li.selected > a span:not(.unreadcount),
html.dark-mode #sections-table tr.selected > td,
html.dark-mode #sections-table tr.selected td a {
	color: var(--pv-on-dark) !important;
}

/* Brand purple on #171226 is only 2.4:1 and disappears; the rail uses the
   light purple in dark mode (4.24:1 against the selected surface). */
html.dark-mode:not(.touch) .listing li.selected > a,
html.dark-mode:not(.touch) .listing tbody tr.selected > td:first-child,
html.dark-mode:not(.touch) .listing:not(.withselection) tbody tr.selected > td.selection + td,
html.dark-mode:not(.touch) .messagelist tbody tr.selected > td:first-child,
html.dark-mode #sections-table tr.selected > td:first-child,
html.dark-mode #mailboxlist li.selected > a,
html.dark-mode .treelist li.selected > a {
	border-left-color: var(--pv-primary-on-dark) !important;
}

html.dark-mode input.form-control:focus-visible,
html.dark-mode textarea.form-control:focus-visible,
html.dark-mode select.form-control:focus-visible {
	border-color: var(--pv-primary-on-dark) !important;
	box-shadow: 0 0 0 3px rgba(169, 155, 245, 0.28) !important;
}

html.dark-mode a:focus-visible,
html.dark-mode button:focus-visible,
html.dark-mode select:focus-visible,
html.dark-mode .btn:focus-visible,
html.dark-mode [role="button"]:focus-visible {
	outline-color: var(--pv-primary-on-dark) !important;
}

html.dark-mode .listing .unreadcount,
html.dark-mode .badge {
	background-color: var(--pv-primary-on-dark) !important;
	color: var(--pv-dark) !important;
}

html.dark-mode #message-header,
html.dark-mode #message-header > .header,
html.dark-mode #message-header .header-content,
html.dark-mode #message-header .header-summary,
html.dark-mode #message-header .header-headers,
html.dark-mode #message-header .header-headers td,
html.dark-mode #message-header .header-links,
html.dark-mode .message-partheaders,
html.dark-mode .message-headerbox {
	background-color: var(--pv-dark-raised) !important;
	border-color: var(--pv-dark-line) !important;
}

html.dark-mode #message-header > .subject,
html.dark-mode #message-header > .subject span.inner,
html.dark-mode #message-header .header-summary,
html.dark-mode #message-header .header-summary > span,
html.dark-mode #message-header .header-headers td.header.from,
html.dark-mode #message-header .header-headers td.header.to,
html.dark-mode #message-header .header-headers td.header.cc,
html.dark-mode .message-subject,
html.dark-mode h2.subject {
	color: var(--pv-on-dark) !important;
}

html.dark-mode #message-header .header-headers td.header-title,
html.dark-mode #message-header .header-headers td.header.date,
html.dark-mode #message-header .header-summary .text-nowrap {
	color: #A8A3BC !important;
}

html.dark-mode #message-header a,
html.dark-mode #message-header .header-links a,
html.dark-mode #message-header .header-summary a {
	color: var(--pv-primary-on-dark) !important;
}

/* Border-colour deliberately absent — see FORM CONTROL BOUNDARIES. This rule
   is a second, more specific dark declaration of the same three controls, and
   it kept setting --pv-dark-line (1.31:1) out from under the boundary rule.
   Two places declaring one property is how the boundary drifted below the
   floor in the first place. */
html.dark-mode input.form-control,
html.dark-mode select.form-control,
html.dark-mode textarea.form-control {
	background-color: var(--pv-dark) !important;
	color: var(--pv-on-dark) !important;
}

html.dark-mode .ui-dialog,
html.dark-mode .popupmenu,
html.dark-mode .popover {
	background-color: var(--pv-dark-raised) !important;
	color: var(--pv-on-dark) !important;
	border-color: var(--pv-dark-line) !important;
}

/* Dark-mode login: gradient already dark, keep the light wordmark and
   darken the card. */
/* THE LOGIN PAGE HAS NO DARK MODE — deliberately, and there is nothing here.
   Four html.dark-mode #login-form blocks used to live at this spot, from back
   when the login page was an ordinary light card that needed a dark twin. The
   redesign replaced that card with glass over a fixed dark shader, but it
   rewrote the LOGIN PAGE section only; these lived down here and survived,
   so in dark mode they were still repainting the card opaque
   (--pv-dark-raised over the glass), filling the inputs and the icons with
   --pv-dark, and re-colouring the icon. That is why the two modes diverged.
   The card is pinned mode-independent instead — see LOGIN PAGE. Do not add
   dark-mode rules for #login-form; if one seems necessary, the pinned tokens
   there are the thing to change. */

/* The popover header plate is white in light mode; in dark mode keep it
   dark and swap the wordmark to the light artwork. */
html.dark-mode #layout-menu .popover-header {
	background-color: #100C1C !important;
}

html.dark-mode #layout-menu .popover-header #logo {
	content: url("../images/logo-icon-dark.svg");
}

/* =========================================================================
   ISPCONFIG3 PLUGIN PAGES
   account · autoreply · pass · spam · fetchmail · filter · forward · wblist

   These render the Settings pages users actually visit. They resolve their
   own skin folder through Roundcube's skin chain; because this skin
   deliberately ships no plugins/ directory, they fall back to their
   skins/elastic/ assets and keep working untouched across ISPConfig
   updates. We brand them from here instead of forking their templates.

   !important is required throughout this block: Roundcube injects plugin
   stylesheets as <link> tags AFTER this file.
   ========================================================================= */

/* Shared settings-form shell used by every plugin */
.formcontainer .formcontent,
#pass_form, #autoreply_form, #filter_form, #forward_form,
#spam_form, #wblist_form, #fetchmail_form, #account_form {
	border-radius: var(--pv-radius);
}

.formcontainer .formbuttons {
	border-top: 1px solid var(--pv-line);
	padding-top: 14px;
}

.propform td.title,
.propform label,
.formcontent label {
	color: var(--pv-muted);
	font-weight: 500;
}

/* The plugin tables (filter, spam, wblist, fetchmail) hardcode a pale blue
   selection — #ebf9ff. They now use the same state-system values as every
   other list rather than a retint of their own, including the rail. */
.records-table tr:not(.selected):hover > td,
#rule-table tr:not(.selected):hover > td,
#fetch-table tr:not(.selected):hover > td {
	background-color: rgba(70, 50, 218, 0.06) !important;
}

.records-table tr.selected > td,
#rule-table tr.selected > td,
#fetch-table tr.selected > td {
	background-color: rgba(70, 50, 218, 0.16) !important;
	color: var(--pv-ink) !important;
	box-shadow: none !important;
}

.records-table tr > td:first-child,
#rule-table tr > td:first-child,
#fetch-table tr > td:first-child {
	border-left: 3px solid transparent !important;
}

.records-table tr.selected > td:first-child,
#rule-table tr.selected > td:first-child,
#fetch-table tr.selected > td:first-child {
	border-left-color: var(--pv-primary) !important;
}

html.dark-mode .records-table tr:not(.selected):hover > td,
html.dark-mode #rule-table tr:not(.selected):hover > td,
html.dark-mode #fetch-table tr:not(.selected):hover > td {
	background-color: rgba(169, 155, 245, 0.10) !important;
}

html.dark-mode .records-table tr.selected > td,
html.dark-mode #rule-table tr.selected > td,
html.dark-mode #fetch-table tr.selected > td {
	background-color: rgba(169, 155, 245, 0.30) !important;
	color: var(--pv-on-dark) !important;
}

html.dark-mode .records-table tr.selected > td:first-child,
html.dark-mode #rule-table tr.selected > td:first-child,
html.dark-mode #fetch-table tr.selected > td:first-child {
	border-left-color: var(--pv-primary-on-dark) !important;
}

.records-table thead td,
.records-table thead th,
#rule-table thead td,
#fetch-table thead td {
	background-color: #F5F4FB !important;
	color: var(--pv-muted) !important;
	font-weight: 600 !important;
	border-bottom: 1px solid var(--pv-line) !important;
}

html.dark-mode .records-table thead td,
html.dark-mode .records-table thead th,
html.dark-mode #rule-table thead td,
html.dark-mode #fetch-table thead td {
	background-color: var(--pv-dark) !important;
	color: #A8A3BC !important;
	border-bottom-color: var(--pv-dark-line) !important;
}

/* Enabled / disabled status glyphs (filter, wblist, fetchmail).
   Shape already differs (check vs cross) so colour is a second cue, not
   the only one. */
#rule-table a.button.icon.status-enabled:before,
#fetch-table a.button.icon.status-enabled:before {
	color: #1E9E62 !important;
}

#rule-table a.button.icon.status-disabled:before,
#fetch-table a.button.icon.status-disabled:before {
	color: var(--pv-muted) !important;
}

/* wblist: whitelist / blacklist markers */
#rule-table a.button.icon.whitelist:before {
	color: #1E9E62 !important;
}

#rule-table a.button.icon.blacklist:before {
	color: var(--pv-cta-600) !important;
}

/* ispconfig3_pass — password strength meter (jQuery UI progressbar)
   -------------------------------------------------------------------------
   COLOUR HERE IS A DELIBERATE EXCEPTION. THE SWEEPS MUST NOT FLATTEN IT.
   Everywhere else in this skin, coral is the CTA colour only and amber is the
   flag/attention accent — and a future stock-accent sweep will see red, amber
   and green in a component and want to replace them with a brand hue. Do not.
   A strength meter is a SEMANTIC SCALE: the hue is the information. A bar in
   one flat colour that only grows longer says "more" but not "safe", which is
   the entire point of the control. Red -> amber -> green is the convention
   users already read, so it stays.

   The scale is the PLUGIN'S, not ours, and that is on purpose. pass.js sets
   the fill inline on keyup from chkPass():
       0-20 #DA4F49 · 21-40 #FAA732 · 41-60 #FAF332 · 61-80 #5BB7A9 · 81+ #5BB75B
   Owning a copy of those five colours here would mean owning a copy of the
   thresholds too, and they would drift the first time the plugin is updated.
   So we style the GEOMETRY and let the plugin own the meaning.

   WHAT WAS WRONG WAS ALL MINE. The previous version of this block set
   `background: var(--pv-gradient) !important` on the value, which beat the
   plugin's inline colour and replaced the whole scale with one purple gradient
   — the meter still grew but no longer said anything. It also pinned
   border-radius to 999px, and it carried rules for `.weak`/`.medium` classes
   that pass.js has never set: written speculatively against a mechanism that
   was never checked. The third symptom, the white glow, is Elastic's:
   `.ui-widget { box-shadow: 3px 3px 5px #f1f3f4 }`, a light-mode drop shadow
   that reads as a halo on a dark panel.

   CONTRAST. Measured, fill against the track it sits in:
       dark track  #302748   red 3.44 · orange 7.05 · yellow 11.88 · green 5.54
       light track #E2E0EC   red 3.10 · orange 1.51 · yellow  1.11 · green 1.92
   The bright stops are nearly invisible on a light groove — no single track
   colour can serve fills that span that range. Rather than darken the groove
   on a light form, the BOUNDARY carries the contrast and the FILL carries the
   meaning: a 1px inset edge on the bar in light mode, which is defined
   regardless of hue and satisfies the 3:1 that 1.4.11 asks of the component. */
#pass-check,
#pass-check .ui-progressbar,
.ui-progressbar {
	background-color: var(--pv-line) !important;
	/* THE RING LIVES ON THE TRACK'S BORDER, NOT ON THE FILL.
	   It used to be an inset box-shadow on the fill. A border on a child is
	   inside the parent's `overflow: hidden`, so the track's 6px corners
	   clipped the fill AND the ring with it, and the outline broke at all four
	   corners — worst at 100%, and absent entirely at 0% because there was no
	   fill to draw it on. A border on the TRACK is outside that clip by
	   definition, so it is unbroken at every fill level including empty. */
	border: 1px solid var(--pv-control-line) !important;
	box-sizing: border-box;
	/* Matches #newpasswd beside it, and every other control in the skin. */
	border-radius: var(--pv-radius-sm) !important;
	box-shadow: none !important;
	overflow: hidden;
	height: 2.4rem;
}

/* NO background-color here: the plugin's inline colour must win. Only the
   gradient is cleared, and only because the old rule left one behind.
   The radius is the track's INNER radius (6px frame minus the 1px border), so
   the fill's leading corners follow the groove instead of being sliced flat by
   the clip. The trailing edge stays square: that is where the value ends. */
#pass-check .ui-progressbar-value,
.ui-progressbar .ui-progressbar-value {
	background-image: none !important;
	border: 0 !important;
	border-radius: calc(var(--pv-radius-sm) - 1px) 0 0 calc(var(--pv-radius-sm) - 1px) !important;
	margin: 0 !important;
	box-shadow: none !important;
	transition: width .18s ease;
}

/* Light mode only: the bright stops measure 1.11-1.92:1 against a light
   groove, so the END of the fill needs marking or you cannot see how full the
   bar is. A trailing edge does that without touching the corners, which is
   what the inset ring got wrong. */
html:not(.dark-mode) #pass-check .ui-progressbar-value,
html:not(.dark-mode) .ui-progressbar .ui-progressbar-value {
	border-right: 1px solid rgba(26, 22, 38, 0.45) !important;
}

html.dark-mode #pass-check,
html.dark-mode .ui-progressbar {
	background-color: var(--pv-dark-line) !important;
}

#newpasswd {
	border-radius: var(--pv-radius-sm) !important;
}

/* Password requirements line, inserted by privatily_passhint.js. Clears the
   floated field and meter above it (the plugin's pass.css floats them), and
   uses the mode-aware muted ink so it reads in both modes without a dark twin.
   Measured: 6.66:1 light, 7.50:1 dark. */
.pv-pass-hint {
	clear: both;
	display: block;
	padding-top: 0.55rem;
	font-size: 0.82rem;
	line-height: 1.45;
	color: var(--pv-muted) !important;
	max-width: 46ch;
}

/* ispconfig3_autoreply — jQuery UI datepicker / datetime widget */
.ui-datetime,
.ui-datepicker {
	border-radius: var(--pv-radius) !important;
	border: 1px solid var(--pv-line) !important;
	box-shadow: 0 12px 32px rgba(12, 8, 32, .18) !important;
	font-family: var(--pv-font) !important;
}

/* :not(.ui-progressbar-value) — jQuery UI puts `ui-widget-header` on the FILL
   of a progressbar as well as on a datepicker's title bar, so this rule was
   painting the password strength meter brand purple with a 10px/10px/0/0
   radius. That was the real source of both the "odd border radius" and the
   flat purple fill: a selector written for one widget reaching another that
   happens to share a utility class. */
.ui-datepicker .ui-datepicker-header,
.ui-datetime .ui-datepicker-header,
.ui-widget-header:not(.ui-progressbar-value) {
	background: var(--pv-primary) !important;
	background-image: none !important;
	color: #fff !important;
	border: none !important;
	border-radius: var(--pv-radius) var(--pv-radius) 0 0 !important;
}

.ui-datepicker .ui-datepicker-header a,
.ui-datepicker .ui-datepicker-title {
	color: #fff !important;
}

.ui-datepicker td a.ui-state-active,
.ui-datepicker td .ui-state-active,
.ui-state-active {
	background: var(--pv-primary) !important;
	background-image: none !important;
	border-color: var(--pv-primary) !important;
	color: #fff !important;
	border-radius: var(--pv-radius-sm) !important;
}

.ui-datepicker td a.ui-state-hover,
.ui-state-hover {
	background: var(--pv-primary-tint) !important;
	background-image: none !important;
	border-color: var(--pv-primary-300) !important;
	border-radius: var(--pv-radius-sm) !important;
}

.ui-datepicker td a.ui-state-highlight,
.ui-state-highlight {
	background: rgba(255, 167, 79, .22) !important;
	background-image: none !important;
	border-color: var(--pv-accent) !important;
}

html.dark-mode .ui-datetime,
html.dark-mode .ui-datepicker {
	background: var(--pv-dark-raised) !important;
	border-color: var(--pv-dark-line) !important;
	color: var(--pv-on-dark) !important;
}

/* ispconfig3_account previously coloured its settings-list icon brand purple.
   That selector also matches Roundcube's own "Account" row in Settings, so a
   single icon rendered accented while every sibling was dark — it read as
   selected when it was not. Accent on an icon now means selected and nothing
   else, so this is deliberately left to inherit like every other icon. */

/* Plugin action buttons (add/delete rows in filter, wblist, fetchmail,
   forward) inherit .btn — make deletes read as destructive without
   relying on colour alone (the icon already differs). */
#rule-table a.button.icon.delete:before,
#fetch-table a.button.icon.delete:before,
a.button.icon.delete:before {
	color: var(--pv-cta-600) !important;
}

/* =========================================================================
   ELASTIC STOCK-ACCENT SWEEP
   -------------------------------------------------------------------------
   Elastic's palette (styles/colors.less):
       @color-main       #37beff   50 uses in the compiled CSS
       @color-link       #00acff    3 uses
       @color-main-dark  #006a9d    8 uses
       focus rail        #9ddfff    1 use
       focus glow        rgba(55,190,255,.25)  22 uses
   Every one of those was enumerated from the compiled stylesheet and is
   answered below, rather than fixing only the places that happen to be
   visible on screen. If Elastic adds a new accent usage in an upgrade it will
   show through as blue — re-run the enumeration (see UPGRADE.md) to find it.
   ========================================================================= */

/* --- solid accent backgrounds ------------------------------------------- */
.floating-action-buttons a.button,
.ui-slider .ui-slider-handle.ui-state-active,
.ui-menu .ui-state-active,
.popover .menu li a:not(.disabled):hover,
.popover .menu .dropbutton a.dropdown:hover,
.popupmenu .listing li > a:not(.disabled):hover,
.popupmenu .listing li.selected,
.googie_list li.googie_list_onhover,
#messagestack .alert-info.information,
div.tox .tox-dialog__footer .tox-button,
div.tox .tox-dialog__footer .tox-button:focus:not(:disabled) {
	background-color: var(--pv-primary) !important;
	background-image: none !important;
	border-color: var(--pv-primary) !important;
	color: #fff !important;
}

/* The quota meter at the bottom of the folder list. */
.quota-widget .value {
	background-color: var(--pv-primary) !important;
	background-image: none !important;
}

.quota-widget .value.warning,
.quota-widget .value.critical {
	background-color: var(--pv-cta-600) !important;
}

/* Dropdown menus follow the same state system as every other list, and the
   ink is mode-aware. It was pinned to the light ink, which on a dark popup
   measured 1.82:1 — the "Export" item in the More menu was unreadable on
   hover. Light: 13.98:1. Dark: 7.54:1. */
.popover .menu li a:not(.disabled):hover,
.popupmenu .listing li > a:not(.disabled):hover,
.popupmenu .listing li.selected > a,
.popupmenu .listing li.selected {
	background-color: rgba(70, 50, 218, 0.16) !important;
	color: var(--pv-ink) !important;
	border-color: transparent !important;
	box-shadow: none !important;
}

html.dark-mode .popover .menu li a:not(.disabled):hover,
html.dark-mode .popupmenu .listing li > a:not(.disabled):hover,
html.dark-mode .popupmenu .listing li.selected > a,
html.dark-mode .popupmenu .listing li.selected,
html.dark-mode .popover .menu li a:not(.disabled):hover *,
html.dark-mode .popupmenu .listing li > a:not(.disabled):hover * {
	background-color: rgba(169, 155, 245, 0.30) !important;
	color: var(--pv-on-dark) !important;
}

.popover .menu li a:not(.disabled):hover *,
.popupmenu .listing li > a:not(.disabled):hover * {
	color: var(--pv-ink) !important;
	background-color: transparent !important;
}

/* --- accent focus rings --------------------------------------------------
   Re-colouring Elastic's accent only. The ring VALUES come from the state
   system above, so these match every other focus ring in the interface.
   `.tagedit-list[tabindex="-1"]` is deliberately absent: it is a permanent
   attribute, not a focus state, so including it drew a ring on the widget at
   rest. Its focus is handled by the container rule in the state system. */
.formcontent.raweditor .CodeMirror-focused,
.custom-file-input:focus-visible ~ .custom-file-label,
.custom-switch .custom-control-input:focus-visible:not(:checked) ~ .custom-control-label::before,
div.tox.focused {
	border-color: var(--pv-primary) !important;
	box-shadow: 0 0 0 3px rgba(70, 50, 218, 0.28) !important;
}

/* Elastic's focus rail on list rows (#9ddfff) is deliberately NOT re-coloured
   here. It fired on the row Roundcube auto-focuses at load, which reads as
   selection; the three-state block above renders it transparent instead. */

/* --- status toasts ------------------------------------------------------
   Roundcube's stock toast colours fail AA with their own white text:
     .alert-danger  white on #ff5552 = 3.15:1
     .alert-success white on #41b849 = 2.57:1
   Neither had been reported — they only appear transiently, which is exactly
   why measuring beats looking. Deepened to keep the same semantics and the
   same white ink, now 5.12:1 and 5.14:1. The danger tone is a darkened
   member of the coral family so it still reads as ours. */
#messagestack .alert-danger,
.ui.alert.boxerror {
	background-color: #C2413F !important;
	color: #fff !important;
}

#messagestack .alert-success,
.ui.alert.boxconfirmation {
	background-color: #1E7E34 !important;
	color: #fff !important;
}

#messagestack .alert-danger > i.icon:before,
#messagestack .alert-success > i.icon:before {
	color: #fff !important;
}

/* Warning keeps dark ink on yellow, which already measures well. */
#messagestack .alert-warning,
.ui.alert.boxwarning {
	background-color: #FFD452 !important;
	color: #2C363A !important;
}

/* --- accent text --------------------------------------------------------- */
.btn-link,
.ui.alert a:not(.btn),
.ui-datepicker .ui-datepicker-days-cell-over a,
.ui-datepicker .ui-state-highlight,
div.tox .tox-dialog .tox-dialog__body-nav-item--active {
	color: var(--pv-primary) !important;
}

/* --- blockquote bars in messages (main-dark) ----------------------------- */
.message-part blockquote,
.message-htmlpart blockquote {
	border-left-color: var(--pv-primary-300) !important;
	border-right-color: var(--pv-primary-300) !important;
	color: var(--pv-primary-600) !important;
}

/* --- dark mode counterparts ---------------------------------------------- */
html.dark-mode .btn-primary,
html.dark-mode .floating-action-buttons a.button,
html.dark-mode .custom-switch .custom-control-input:checked ~ .custom-control-label::before,
html.dark-mode div.tox .tox-dialog__footer .tox-button {
	background-color: var(--pv-primary) !important;
	border-color: var(--pv-primary) !important;
	color: #fff !important;
}

html.dark-mode .listing li.selected,
html.dark-mode .listing li.selected > a,
html.dark-mode .listing li.selected > div > a,
html.dark-mode .messagelist tr.selected td.subject a,
html.dark-mode .ui-datepicker .ui-state-highlight,
html.dark-mode div.tox .tox-dialog__body-nav-item--active,
html.dark-mode div.tox .tox-collection__item--enabled,
html.dark-mode #taskmenu .action-buttons a {
	color: var(--pv-on-dark) !important;
}

html.dark-mode .multi-input:not(.is-invalid) > .content.focused {
	border-color: var(--pv-primary-on-dark) !important;
	box-shadow: 0 0 0 3px rgba(169, 155, 245, 0.28) !important;
}

html.dark-mode .message-part blockquote,
html.dark-mode .message-htmlpart blockquote {
	border-left-color: var(--pv-primary-on-dark) !important;
	border-right-color: var(--pv-primary-on-dark) !important;
	color: var(--pv-primary-on-dark) !important;
}

/* =========================================================================
   COMPOSE, AND THE THIRD STOCK PALETTE (TINYMCE / OXIDE)
   -------------------------------------------------------------------------
   WHY THE EARLIER SWEEP MISSED THE COMPOSE VIEW.
   That sweep enumerated Elastic's colors.less and answered every use of it.
   TinyMCE is not part of Elastic. It ships its OWN compiled UI skin at
       program/js/tinymce/skins/ui/oxide/skin.min.css
   which TinyMCE injects into the page itself — no skin, no plugin and no
   Roundcube config points at it, so nothing in the skin chain had ever
   referenced its palette. Elastic overrides part of it and leaves the rest.
   Counted on the rendered compose page (getComputedStyle, not by eye):

     OXIDE   #222f3e  ink        141 elements + 59 svg fills   untouched
             #207ab7  ACCENT      17 rules — a THIRD accent blue, distinct
                      #1c6ca1 / #185d8c hover+active, rgba(32,122,183,.x)
             #cccccc  borders · #dee0e2 hover · #c8cbcf active · #f2f2f2 disabled
     ELASTIC light  #f1f3f4 toolbar · #ced4da frame · #8b9fa7 secondary button
     ELASTIC dark   #374549 toolbar+addons · #21292c dialog · #161b1d menu
                    #586e75 enabled · #7c949c frame · #c5d1d3 ink · #4d6066 line

   #374549 is the desaturated grey-green: same family as the pane dividers and
   the quota widget, reached by a different route.

   THE FIX IS TOKENS, NOT A LIST OF COLOURS. Every surface below resolves to
   --pv-surface / --pv-panel / --pv-ink, which are mode-aware, so the dark half
   follows by construction. The toolbar and its menus are lists of buttons, so
   they take THE SAME three states as every other list in the interface —
   rest / hover wash / selected wash + promoted ink — rather than inventing a
   fourth vocabulary. Measured, composited against the real surfaces:

     light  rest #F1EFF7 · ink 15.53:1 · hover 1.10:1 vs rest · enabled 1.29:1
     dark   rest #211A33 · ink 13.57:1 · hover 1.19:1 vs rest · enabled 1.80:1

   REACHABLE SURFACES, all verified open on the live page rather than assumed:
   toolbar, overflow drawer (toolbar_drawer: sliding), font and size menus,
   colour swatch grids, the Color Picker dialog, and the table context toolbar
   (.tox-pop — the table plugin IS loaded, so a pasted table reaches it).
   ========================================================================= */

/* --- frame, toolbar, drawer: square, as asked ---------------------------- */
div.tox.tox-tinymce,
div.tox .tox-editor-container,
div.tox .tox-editor-header,
div.tox .tox-toolbar-overlord,
div.tox .tox-toolbar,
div.tox .tox-toolbar__primary,
div.tox .tox-toolbar__overflow,
div.tox .tox-tbtn,
div.tox .tox-tbtn--select,
div.tox .tox-split-button,
div.tox .tox-split-button__chevron,
div.tox .tox-swatches__picker-btn,
div.tox .tox-toolbar__group {
	border-radius: 0 !important;
}

div.tox .tox-toolbar-overlord,
div.tox .tox-toolbar,
div.tox .tox-toolbar__primary,
div.tox .tox-toolbar__overflow,
html.dark-mode div.tox .tox-toolbar,
html.dark-mode div.tox .tox-toolbar__primary,
html.dark-mode div.tox .tox-toolbar__overflow {
	background-color: var(--pv-surface) !important;
	/* Elastic and oxide both paint the group separator as a background SVG on
	   the toolbar row; drop it and use a real border below, so there is one
	   mechanism for one line. */
	background-image: none !important;
}

/* The oxide default under the toolbar rows is #fff, which showed through at
   the drawer's edges in dark mode. */
html.dark-mode div.tox .tox-toolbar-overlord,
html.dark-mode div.tox .tox-editor-header {
	background-color: var(--pv-surface) !important;
}

/* The editor frame IS the boundary of the message-body field, so it takes the
   control line like every other field. These two rules are more specific than
   the boundary rule and would otherwise silently hold --pv-line. */
div.tox.tox-tinymce {
	border: 1px solid var(--pv-control-line) !important;
}

html.dark-mode div.tox.tox-tinymce {
	border-color: var(--pv-control-line) !important;
}

div.tox .tox-toolbar__primary,
div.tox .tox-toolbar__overflow,
html.dark-mode div.tox .tox-toolbar__primary,
html.dark-mode div.tox .tox-toolbar__overflow {
	border-bottom: 1px solid var(--pv-line) !important;
}

div.tox .tox-toolbar__group:not(:last-of-type),
html.dark-mode div.tox .tox-toolbar__group:not(:last-of-type) {
	border-right: 1px solid var(--pv-line) !important;
}

/* --- toolbar ink: one colour, and the icons follow it -------------------- */
div.tox,
div.tox .tox-tbtn,
div.tox .tox-tbtn--select,
div.tox .tox-split-button,
div.tox .tox-swatches__picker-btn,
div.tox .tox-tbtn__select-label,
div.tox .tox-toolbar-label,
html.dark-mode div.tox .tox-tbtn,
html.dark-mode div.tox .tox-split-button,
html.dark-mode div.tox .tox-swatches__picker-btn {
	color: var(--pv-ink) !important;
}

/* currentColor is the point: state changes the ink once and the glyph follows,
   instead of every state needing a matching fill rule. */
div.tox .tox-tbtn svg,
div.tox .tox-split-button svg,
div.tox .tox-swatches__picker-btn svg,
div.tox .tox-tbtn__icon-wrap svg,
html.dark-mode div.tox .tox-tbtn svg,
html.dark-mode div.tox .tox-split-button svg,
html.dark-mode div.tox .tox-swatches__picker-btn svg {
	fill: currentColor !important;
}

/* html.dark-mode-prefixed, because the ink rule above carries that prefix and
   would otherwise out-specify this one — measured as a disabled button at the
   full 13.57:1, i.e. indistinguishable from an enabled one. */
div.tox .tox-tbtn--disabled,
div.tox .tox-tbtn--disabled svg,
div.tox .tox-tbtn:disabled,
html.dark-mode div.tox .tox-tbtn--disabled,
html.dark-mode div.tox .tox-tbtn--disabled svg,
html.dark-mode div.tox .tox-tbtn:disabled {
	color: var(--pv-muted) !important;
	opacity: .65;
}

/* --- the three states, applied to toolbar buttons ----------------------- */
div.tox .tox-tbtn:hover:not(.tox-tbtn--disabled),
div.tox .tox-tbtn:focus:not(.tox-tbtn--disabled),
div.tox .tox-split-button:hover,
div.tox .tox-split-button:focus,
div.tox .tox-swatches__picker-btn:hover {
	background: rgba(70, 50, 218, 0.06) !important;
	box-shadow: none !important;
	color: var(--pv-ink) !important;
}

/* Enabled PROMOTES THE INK, it does not switch to the accent — the same
   decision the list state system already made, for the same measured reason:
   on the dark selection wash the accent purple reaches only 3.83:1, while the
   promoted ink reaches 7.54:1. Using the accent here would have been a second
   vocabulary for the same state. */
div.tox .tox-tbtn--enabled,
div.tox .tox-tbtn--enabled:hover,
div.tox .tox-tbtn:active {
	background: rgba(70, 50, 218, 0.16) !important;
	color: var(--pv-ink) !important;
	box-shadow: none !important;
}

html.dark-mode div.tox .tox-tbtn:hover:not(.tox-tbtn--disabled),
html.dark-mode div.tox .tox-tbtn:focus:not(.tox-tbtn--disabled),
html.dark-mode div.tox .tox-split-button:hover,
html.dark-mode div.tox .tox-split-button:focus,
html.dark-mode div.tox .tox-swatches__picker-btn:hover {
	background: rgba(169, 155, 245, 0.10) !important;
	color: var(--pv-ink) !important;
}

html.dark-mode div.tox .tox-tbtn--enabled,
html.dark-mode div.tox .tox-tbtn--enabled:hover,
html.dark-mode div.tox .tox-tbtn:active {
	background: rgba(169, 155, 245, 0.30) !important;
	color: var(--pv-ink) !important;
}

/* Focus follows the skin's rule: :focus-visible only, one ring, inset so a
   square button flush against the toolbar edge cannot clip it. */
div.tox .tox-tbtn:focus-visible,
div.tox .tox-split-button:focus-visible {
	outline: 2px solid var(--pv-primary) !important;
	outline-offset: -2px;
	border-radius: 0 !important;
}

html.dark-mode div.tox .tox-tbtn:focus-visible,
html.dark-mode div.tox .tox-split-button:focus-visible {
	outline-color: var(--pv-primary-on-dark) !important;
}

/* --- menus, dialogs and context pops: match the app's own panels --------
   These are the same widget as .popover / .popupmenu, so they take the same
   radius, and the container clips (rule 5 of the state system). */
div.tox .tox-menu,
div.tox .tox-collection,
div.tox .tox-dialog,
div.tox .tox-pop__dialog,
html.dark-mode div.tox .tox-menu,
html.dark-mode div.tox .tox-dialog,
html.dark-mode div.tox .tox-pop__dialog {
	background-color: var(--pv-panel) !important;
	border: 1px solid var(--pv-line) !important;
	border-radius: var(--pv-radius) !important;
	overflow: hidden;
	box-shadow: 0 8px 28px rgba(23, 18, 38, .18) !important;
}

/* .tox-pop__dialog kept oxide's #fff in dark mode — Elastic overrides its
   border and shadow but never its background — so the table context toolbar
   framed a grey-green bar in a white box, and any pop that is NOT fully
   covered by a toolbar rendered #c5d1d3 text on white: 1.56:1. */
html.dark-mode div.tox .tox-pop__dialog .tox-toolbar,
html.dark-mode div.tox .tox-pop__dialog .tox-toolbar__primary {
	background-color: var(--pv-panel) !important;
	border: 0 !important;
}

div.tox .tox-dialog__header,
div.tox .tox-dialog__body,
div.tox .tox-dialog__body-content,
div.tox .tox-dialog__footer,
div.tox .tox-dialog__title,
html.dark-mode div.tox .tox-dialog__header,
html.dark-mode div.tox .tox-dialog__body,
html.dark-mode div.tox .tox-dialog__footer,
html.dark-mode div.tox .tox-dialog__title {
	background-color: var(--pv-panel) !important;
	color: var(--pv-ink) !important;
	border-color: var(--pv-line) !important;
}

div.tox .tox-dialog-wrap__backdrop,
html.dark-mode div.tox .tox-dialog-wrap__backdrop {
	background-color: rgba(23, 18, 38, 0.62) !important;
}

/* Menu rows: same three states as every list. .tox-swatch is excluded from
   every one of these — its background IS the colour the user is picking, and
   painting a state over it would change what they think they are choosing. */
div.tox .tox-collection__item,
html.dark-mode div.tox .tox-collection__item {
	color: var(--pv-ink) !important;
	border-radius: 0 !important;
}

div.tox .tox-collection__item:not(:last-child),
html.dark-mode div.tox .tox-collection__item:not(:last-child) {
	border-bottom-color: var(--pv-line) !important;
}

div.tox .tox-collection__item--active:not(.tox-swatch):not(.tox-collection__item--state-disabled),
html.dark-mode div.tox .tox-collection__item--active:not(.tox-swatch):not(.tox-collection__item--state-disabled) {
	background-color: rgba(70, 50, 218, 0.06) !important;
	color: var(--pv-ink) !important;
}

html.dark-mode div.tox .tox-collection__item--active:not(.tox-swatch):not(.tox-collection__item--state-disabled) {
	background-color: rgba(169, 155, 245, 0.10) !important;
}

div.tox .tox-collection__item--enabled:not(.tox-swatch) {
	background-color: rgba(70, 50, 218, 0.16) !important;
	color: var(--pv-ink) !important;
}

html.dark-mode div.tox .tox-collection__item--enabled:not(.tox-swatch) {
	background-color: rgba(169, 155, 245, 0.30) !important;
	color: var(--pv-ink) !important;
}

div.tox .tox-collection__item-caret svg,
div.tox .tox-collection__item-icon svg,
div.tox .tox-collection__item-checkmark svg,
html.dark-mode div.tox .tox-collection__item-caret svg,
html.dark-mode div.tox .tox-collection__item-icon svg {
	fill: currentColor !important;
}

/* --- OXIDE'S OWN ACCENT (#207ab7 / #1c6ca1 / #185d8c) --------------------
   Enumerated from skin.css, not from what happened to be on screen. Elastic
   never touches these, so they were the last un-branded blue in the product. */
div.tox .tox-button:not(.tox-button--secondary):not(.tox-button--naked),
div.tox .tox-button:not(.tox-button--secondary):not(.tox-button--naked):focus:not(:disabled),
div.tox .tox-dialog__footer .tox-button:not(.tox-button--secondary),
html.dark-mode div.tox .tox-dialog__footer .tox-button:not(.tox-button--secondary) {
	background-color: var(--pv-primary) !important;
	background-image: none !important;
	border-color: var(--pv-primary) !important;
	color: #fff !important;
	border-radius: var(--pv-radius-sm) !important;
}

div.tox .tox-button:not(.tox-button--secondary):not(.tox-button--naked):hover:not(:disabled),
div.tox .tox-button:not(.tox-button--secondary):not(.tox-button--naked):active:not(:disabled),
div.tox .tox-dialog__footer .tox-button:not(.tox-button--secondary):hover:not(:disabled) {
	background-color: var(--pv-primary-600) !important;
	border-color: var(--pv-primary-600) !important;
	color: #fff !important;
}

/* Cancel was rendering IDENTICALLY to Save. My own accent sweep set
   `div.tox .tox-dialog__footer .tox-button` with !important, which beat
   Elastic's more specific but unflagged .tox-button--secondary rule — so the
   Color Picker offered two purple buttons and no way to tell them apart. The
   selectors above now exclude the secondary explicitly. */
div.tox .tox-button.tox-button--secondary,
div.tox .tox-dialog__footer .tox-button.tox-button--secondary,
div.tox .tox-button.tox-button--secondary:focus:not(:disabled),
html.dark-mode div.tox .tox-dialog__footer .tox-button.tox-button--secondary,
div.tox .image-selector button {
	background-color: var(--pv-surface) !important;
	background-image: none !important;
	border-color: var(--pv-control-line) !important;
	color: var(--pv-ink) !important;
	border-radius: var(--pv-radius-sm) !important;
}

div.tox .tox-button.tox-button--secondary:hover:not(:disabled),
div.tox .tox-dialog__footer .tox-button.tox-button--secondary:hover:not(:disabled),
div.tox .image-selector button:hover {
	background-color: var(--pv-surface-2) !important;
	border-color: var(--pv-control-line) !important;
	color: var(--pv-ink) !important;
}

div.tox .tox-naked-btn,
div.tox .tox-dialog__body-content a,
div.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2,
div.tox .tox-dialog__body-nav-item--active,
html.dark-mode div.tox .tox-dialog__body-nav-item--active {
	color: var(--pv-primary) !important;
}

html.dark-mode div.tox .tox-naked-btn,
html.dark-mode div.tox .tox-dialog__body-content a,
html.dark-mode div.tox .tox-dialog__body-nav-item--active {
	color: var(--pv-primary-on-dark) !important;
}

div.tox .tox-dialog__body-nav-item--active {
	border-bottom-color: var(--pv-primary) !important;
}

div.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg,
div.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg {
	fill: var(--pv-primary) !important;
}

div.tox input.tox-checkbox__input:focus + .tox-checkbox__icons {
	box-shadow: inset 0 0 0 1px var(--pv-primary) !important;
}

div.tox .tox-insert-table-picker .tox-insert-table-picker__selected {
	background-color: rgba(70, 50, 218, 0.5) !important;
	border-color: rgba(70, 50, 218, 0.5) !important;
}

div.tox .tox-slider__handle {
	background-color: var(--pv-primary) !important;
	border-color: var(--pv-primary-600) !important;
}

div.tox .tox-color-input span:hover:not([aria-disabled="true"]),
div.tox .tox-color-input span:focus:not([aria-disabled="true"]) {
	border-color: var(--pv-primary) !important;
}

/* --- fields inside TinyMCE dialogs --------------------------------------
   Some carry Roundcube's .form-control class and were already right; the ones
   that do not (the Source-code textarea, listbox selects) were still stock. */
div.tox .tox-textfield,
div.tox .tox-textarea,
div.tox .tox-listboxfield .tox-listbox--select,
div.tox .tox-selectfield select,
div.tox .tox-color-input > input {
	background-color: var(--pv-panel) !important;
	color: var(--pv-ink) !important;
	border-color: var(--pv-control-line) !important;
	font-family: var(--pv-font) !important;
}

div.tox .tox-textfield:focus,
div.tox .tox-textarea:focus,
div.tox .tox-listboxfield .tox-listbox--select:focus,
div.tox .tox-selectfield select:focus {
	border-color: var(--pv-primary) !important;
	box-shadow: 0 0 0 3px rgba(70, 50, 218, 0.28) !important;
	outline: 0 !important;
}

html.dark-mode div.tox .tox-textfield:focus,
html.dark-mode div.tox .tox-textarea:focus,
html.dark-mode div.tox .tox-listboxfield .tox-listbox--select:focus,
html.dark-mode div.tox .tox-selectfield select:focus {
	border-color: var(--pv-primary-on-dark) !important;
	box-shadow: 0 0 0 3px rgba(169, 155, 245, 0.28) !important;
}

div.tox .tox-label,
div.tox .tox-toolbar-label,
html.dark-mode div.tox .tox-label {
	color: var(--pv-muted) !important;
}

/* --- the PLAIN-TEXT editor's toolbar ------------------------------------
   Not TinyMCE at all: Elastic builds its own one-button toolbar for plain-text
   textareas (html_editor_init in ui.js) and gives it the same stock #f1f3f4 /
   #ced4da pair. It is the toolbar a user sees the moment they switch compose
   to plain text, and it lives inside the Settings preference frame too, so it
   would have been missed by looking only at the HTML editor. */
.html-editor .editor-toolbar,
html.dark-mode .html-editor .editor-toolbar {
	background-color: var(--pv-surface) !important;
	border-color: var(--pv-line) !important;
	border-radius: 0 !important;
}

.html-editor .editor-toolbar a,
html.dark-mode .html-editor .editor-toolbar a {
	color: var(--pv-ink) !important;
	border-radius: 0 !important;
}

.html-editor .editor-toolbar a:hover,
.html-editor .editor-toolbar a:focus {
	background-color: rgba(70, 50, 218, 0.06) !important;
}

html.dark-mode .html-editor .editor-toolbar a:hover,
html.dark-mode .html-editor .editor-toolbar a:focus {
	background-color: rgba(169, 155, 245, 0.10) !important;
}

/* --- compose header rows ------------------------------------------------
   Square, and the addon buttons stop being a stock grey slab. The field and
   its addon are squared TOGETHER: squaring only the addon would leave the
   select rounded on one end and flat on the other, which is a worse artefact
   than the one being fixed. */
#compose-headers .input-group > .form-control,
#compose-headers .input-group > ul.recipient-input,
#compose-headers .input-group > select,
#compose-headers .input-group-prepend > .input-group-text,
#compose-headers .input-group-append > .input-group-text,
#compose-headers .input-group-prepend > a,
#compose-headers .input-group-append > a,
#compose-headers input.form-control,
#compose-headers select.form-control,
#compose-headers ul.recipient-input {
	border-radius: 0 !important;
}

/* The addon's border must match the border of the field it is welded to.
   Elastic gives the addon its own dark value (#7c949c) while the field beside
   it takes ours, so in dark mode the two halves of one control were outlined
   in different colours. Only visible with transitions frozen — see the note in
   the compose walk. */
#compose-headers .input-group-text,
#compose-headers .input-group-append > a.input-group-text,
#compose-headers .input-group-prepend > a.input-group-text,
html.dark-mode #compose-headers .input-group-text,
html.dark-mode #compose-headers .input-group-append > a.input-group-text,
html.dark-mode #compose-headers .input-group-prepend > a.input-group-text {
	background-color: var(--pv-surface) !important;
	color: var(--pv-primary) !important;
}

#compose-headers .input-group-text,
#compose-headers .input-group-append > a.input-group-text,
#compose-headers .input-group-prepend > a.input-group-text,
html.dark-mode #compose-headers .input-group-text,
html.dark-mode #compose-headers .input-group-append > a.input-group-text,
html.dark-mode #compose-headers .input-group-prepend > a.input-group-text {
	border-color: var(--pv-control-line) !important;
}

/* The bare <input> inside the recipient widget — the field you actually type a
   recipient into — kept Elastic's dark ink (#c5d1d3, a teal-grey) instead of
   ours, so the address being typed was a different colour from the chip it
   became a moment later. */
html.dark-mode .recipient-input input,
html.dark-mode .multi-input input,
html.dark-mode .tagedit-list input {
	color: var(--pv-on-dark) !important;
}

/* Elastic draws the RIGHT-hand sidebar's divider with border-left, and the
   dark-mode divider rule only ever covered border-right — so the compose
   options pane was separated by a stock blue-grey line. */
html.dark-mode #layout-sidebar.sidebar-right,
html.dark-mode .listbox.sidebar-right {
	border-left-color: var(--pv-dark-line) !important;
}

/* Toolbar overflow menu separators (the mobile/narrow toolbar list). */
#toolbar-menu > li,
.menu.toolbar > li,
html.dark-mode #toolbar-menu > li,
html.dark-mode .menu.toolbar > li {
	border-bottom-color: var(--pv-line) !important;
}

html.dark-mode #compose-headers .input-group-text {
	color: var(--pv-primary-on-dark) !important;
}

#compose-headers a.input-group-text:hover,
#compose-headers a.input-group-text:focus {
	background-color: var(--pv-surface-2) !important;
}

/* Recipient chips carried the same stock grey as the addons. */
.recipient-input li.recipient,
.tagedit-list li.tagedit-listelement-old,
html.dark-mode .recipient-input li.recipient,
html.dark-mode .tagedit-list li.tagedit-listelement-old {
	background-color: var(--pv-surface) !important;
	border-color: var(--pv-line) !important;
	color: var(--pv-ink) !important;
}

/* Attachment drop zone: dashed edges read weaker than solid ones, so this is
   the one place the control line is worth spending. Elastic drew it at
   #d4dbde (1.35:1 on white) and #4d6066 in dark. */
#compose-attachments.file-upload,
.file-upload.droptarget,
html.dark-mode #compose-attachments.file-upload,
html.dark-mode .file-upload.droptarget {
	border-color: var(--pv-control-line) !important;
}

#compose-attachments .hint,
.file-upload .hint,
html.dark-mode #compose-attachments .hint,
html.dark-mode .file-upload .hint {
	color: var(--pv-muted) !important;
}

/* =========================================================================
   PRINT — keep it ink-cheap and legible; never print the gradient.
   ========================================================================= */

@media print {
	#layout-content.no-navbar,
	body.task-login #layout {
		background: #fff !important;
	}

	#layout-content.no-navbar #logo,
	#layout-menu .popover-header #logo {
		content: url("../images/logo-light.svg") !important;
	}

	.toolbar, .header, #taskmenu, #layout-menu {
		background: #fff !important;
		color: #000 !important;
	}
}

/* =========================================================================
   REDUCED MOTION
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {
	#login-form input.form-control,
	#login-form .btn-primary,
	.btn {
		transition: none !important;
	}
}
