/* Public Dynamic CSS v1.0.2 */
/* Global styles */
/*
Dark Blue: #00437a
Blue:      #005c9b
Purple:    #7d0082
*/

html { width: 100%; height: 100%; }
body.login-page {
	width: 100%;
	height: 100%;
	font-family: "open_sansregular", "Segoe UI","Helvetica Neue",Arial,sans-serif;
	color: #2d2d2b;
	background: #1d1d1d url('https://nwm.tools/themes/default/images/login-background-standard.jpg') no-repeat center center;
    background-size: cover !important;
	background-attachment: fixed !important;
}
body.login-page a, body.login-page a:link { color: #2d2d2b; text-decoration: none; }
body.login-page a:visited { color: #2d2d2b }
body.login-page a:focus { color: #2d2d2b; }
body.login-page a:hover { color: #7d0082; }
body.login-page a:active { color: #2d2d2b; }
body.login-page img, body.login-page iframe { max-width: 100% }
body.login-page.fa { min-width: 16px; }
body.login-page .col-add { display: none; }
body.login-page .container {
	width: 100%;
    height: 100%;
	max-width: 5120px;
    padding-right: 0;
    padding-left: 0;
}

body.login-page .navbar {
	background-color: #00437a !important;
}
body.login-page .landing-container {
	height: 100%;
	height: calc(100% - 35px);
	padding-top: 15px;
}
body.login-page .landing-row{
	height: 100%;
}
body.login-page .col-logo {
	text-align: center;
}
body.login-page .logo, .login-wrapper {
	visibility: hidden;
}
body.login-page .login-wrapper {
	padding: 16px 16px 0;
    background: #ffffff;
    background: rgba(255, 255, 255, 0);
    border: 1px solid #00437a;
    -moz-border-radius: 3px;
    -webkit-border-radius: 3px;
    border-radius: 3px;
    -moz-box-shadow: 3px 3px 5px -1px rgba(0,0,0,0.4);
    -webkit-box-shadow: 3px 3px 5px -1px rgba(0,0,0,0.4);
    box-shadow: 3px 3px 5px -1px rgba(0,0,0,0.4);
}
body.login-page .login-wrapper h1 {
	color: #2d2d2b;
	font-size: 2.1rem;
}
body.login-page .login-wrapper p {
	color: #fff;
}
body.login-page .login-wrapper .input-group-addon {
	min-width: 42px;
	color: #fff;
	background-color: #00437a;
	border: 0px solid rgba(0,0,0,.15);
	text-align: center;
    align-items: center;
    justify-content: center;
}
body.login-page .login-wrapper .form-control {
	border: 1px solid #00437a;
}
body.login-page .login-wrapper .form-control:hover,
body.login-page .login-wrapper .form-control:focus {
	border: 1px solid #80bdff;
}
body.login-page .login-wrapper .btn {
	cursor: pointer;
    background: #00437a;
}
body.login-page .login-wrapper .btn:hover {
    background: #00437a;
    border: 1px solid #00437a;
    opacity: 0.85;
}
body.login-page .form-msg {
	min-height: 28px;
    margin-top: .5rem;
    font-weight: bold;
    color: #cc0000;
}
body.login-page .form-msg #js-msg {
	display: none;
}
body.login-page .loader {
    display: none;
    border: 10px solid #fff;
    border-radius: 50%;
    border-top: 10px solid #00437a;
    width: 48px;
    height: 48px;
    -webkit-animation: loader-spin 1.25s linear infinite;
    animation: loader-spin 1.25s linear infinite;
}
body.login-page .loader-login {
    width: 36px;
    height: 36px;
    border: 8px solid #fff;
    border-top: 8px solid #00437a;
    margin: 0 8px;
}
@-webkit-keyframes loader-spin {
  0% { -webkit-transform: rotate(0deg); }
  100% { -webkit-transform: rotate(360deg); }
}
@keyframes loader-spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

body.login-page .footer {
	width: 100%;
	margin-right: auto;
    margin-left: auto;
    padding: 8px 15px;
	font-size: 0.8rem;
	color: #2d2d2b;
	background-color: #00437a !important;
}
body.login-page .footer a, body.login-page .footer a:link { color: #2d2d2b; }
body.login-page .footer a:hover { color: #005c9b; }

body.login-page .tooltip.in {
	opacity: 1;
}
body.login-page .login-contact,
body.login-page #dialog-slider-warning {
	display: none;
}
.login-page .grecaptcha-badge {
	z-index: 1031;
}
body.login-page .row-public,
body.login-page .student-menu-flyout {
    display: none!important;
}

/* Google Sign In Button */
.gsi-material-button {
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
  -webkit-appearance: none;
  background-color: #131314;
  background-image: none;
  border: 1px solid #747775;
  -webkit-border-radius: 4px;
  border-radius: 4px;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  color: #e3e3e3;
  cursor: pointer;
  font-family: 'Roboto', arial, sans-serif;
  font-size: 14px;
  height: 40px;
  letter-spacing: 0.25px;
  outline: none;
  overflow: hidden;
  padding: 0 12px;
  position: relative;
  text-align: center;
  -webkit-transition: background-color .218s, border-color .218s, box-shadow .218s;
  transition: background-color .218s, border-color .218s, box-shadow .218s;
  vertical-align: middle;
  white-space: nowrap;
  width: auto;
  max-width: 400px;
  min-width: min-content;
  border-color: #8e918f;
  width: 100%;
  margin: 15px 0;
}
.gsi-material-button .gsi-material-button-icon {
  height: 20px;
  margin-right: 10px;
  min-width: 20px;
  width: 20px;
}
.gsi-material-button .gsi-material-button-content-wrapper {
  -webkit-align-items: center;
  align-items: center;
  display: flex;
  -webkit-flex-direction: row;
  flex-direction: row;
  -webkit-flex-wrap: nowrap;
  flex-wrap: nowrap;
  height: 100%;
  justify-content: center;
  position: relative;
  width: 100%;
}
.gsi-material-button .gsi-material-button-contents {
  -webkit-flex-grow: 0;
  flex-grow: 0;
  font-family: 'Roboto', arial, sans-serif;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: top;
}
.gsi-material-button .gsi-material-button-state {
  -webkit-transition: opacity .218s;
  transition: opacity .218s;
  bottom: 0;
  left: 0;
  opacity: 0;
  position: absolute;
  right: 0;
  top: 0;
}
.gsi-material-button:disabled {
  cursor: default;
  background-color: #13131461;
  border-color: #8e918f1f;
}
.gsi-material-button:disabled .gsi-material-button-state {
  background-color: #e3e3e31f;
}
.gsi-material-button:disabled .gsi-material-button-contents {
  opacity: 38%;
}
.gsi-material-button:disabled .gsi-material-button-icon {
  opacity: 38%;
}
.gsi-material-button:not(:disabled):active .gsi-material-button-state, 
.gsi-material-button:not(:disabled):focus .gsi-material-button-state {
  background-color: white;
  opacity: 12%;
}
.gsi-material-button:not(:disabled):hover {
  -webkit-box-shadow: 0 1px 2px 0 rgba(60, 64, 67, .30), 0 1px 3px 1px rgba(60, 64, 67, .15);
  box-shadow: 0 1px 2px 0 rgba(60, 64, 67, .30), 0 1px 3px 1px rgba(60, 64, 67, .15);
}
.gsi-material-button:not(:disabled):hover .gsi-material-button-state {
  background-color: white;
  opacity: 8%;
}
.google_login_or {
  margin-bottom: 15px;
  display: block;
  font-size: 20px;
  text-transform: uppercase;
  text-align: center;
}

/* Scroll bars */
::-webkit-scrollbar {
    width: 10px;
	background: #fff;
}
::-webkit-scrollbar-track {
	-webkit-box-shadow: inset 0 0 14px #d0d0d0;
}

::-webkit-scrollbar-thumb {
    -webkit-box-shadow: inset 0 0 10px #006fbb;
    background: #fff;
	border-radius: 3px;
}

/* Media Queries */

/* Bootstrap Standard Breakpoints */
@media (min-width: 576px) {
	body.login-page { background: #1d1d1d url('https://nwm.tools/themes/default/images/login-background-small.jpg') no-repeat center center; }
}
@media (min-width: 768px) {
	body.login-page { background: #1d1d1d url('https://nwm.tools/themes/default/images/login-background-small.jpg') no-repeat center center; }
}
@media (min-width: 992px) {
	body.login-page { background: #1d1d1d url('https://nwm.tools/themes/default/images/login-background-small.jpg') no-repeat center center; }
}
@media (min-width: 1200px) {
	body.login-page { background: #1d1d1d url('https://nwm.tools/themes/default/images/login-background-standard.jpg') no-repeat center center; }
}

/* Custom Breakpoints */
@media (orientation: landscape) {
	body.login-page .col-last { height: 70px; }
}
@media (min-width: 1921px) {
	body.login-page { background: #1d1d1d url('https://nwm.tools/themes/default/images/login-background-large.jpg') no-repeat center center; }
}
@media (min-width: 319px) and (orientation: portrait) {
	body.login-page { background: #1d1d1d url('https://nwm.tools/themes/default/images/login-background-portrait-standard.jpg') no-repeat center center; }
}
@media (min-width: 1024px) and (orientation: portrait) {
	body.login-page { background: #1d1d1d url('https://nwm.tools/themes/default/images/login-background-portrait-large.jpg') no-repeat center center; }
}
@media (max-width: 991px) {
	body.login-page .col-md-2, body.login-page .col-md-4, body.login-page .col-md-6 {
		    width: 100%;
			max-width: 100%;
			-ms-flex: 0 0 100%;
			flex: 0 0 100%;
	}
	body.login-page .col-logo img { max-width: 30%; }
	body.login-page .col-spacer { display: none; }
	body.login-page .col-add { display: block; }
	body.login-page .align-self-center {
		-ms-flex-item-align: auto !important;
		align-self: auto !important;
	}
	body.login-page .footer, body.login-page .footer .text-right {
		text-align: center !IMPORTANT;
	}
	body.login-page .login-wrapper h1 { font-size: 1.35rem; }
	body.login-page .col-last { height: 90px; }
}
@media (max-width: 575px) {
	body.login-page .login-wrapper h1 { font-size: 1.25rem; }
}
/* Front styles */

/* Variables */
:root {
	--theme-colour-text: #2d2d2b;
	--theme-colour-main: #00437a;
	--theme-colour-main-light: #f8fbfd;
	--theme-colour-link: #005c9b;
	--theme-colour-link-hover: #7d0082;
	--theme-colour-background: #ffffff;
	--theme-colour-light-blue: #099ad3;
	--theme-colour-lighter-blue: #03b7ef;
}

/* Global */
body {
    background: #1d1d1d;
    font-family: "open_sansregular", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
img, iframe {
	max-width: 100%;
}
.relative {
    position: relative;
}
.container img {
    margin: 0;
}
a, a:link, a:visited, a:focus {
	color: var(--theme-colour-main);
	transition: color 0.35s;
	text-decoration: none;
}
a:hover {
	color: var(--theme-colour-link-hover);
	transition: color 0.25s;
}
.btn-primary.active.focus, .btn-primary.active:focus, .btn-primary.active:hover, .btn-primary:active.focus, .btn-primary:active:focus, .btn-primary:active:hover, .open>.dropdown-toggle.btn-primary.focus, .open>.dropdown-toggle.btn-primary:focus, .open>.dropdown-toggle.btn-primary:hover {
    color: #fff;
    background-color: rgb(97,97,97);
    border: 1px solid transparent;
}

/* Grid adjustment */
@media screen and (max-width: 814px) {
	.row {
		margin-right: 0;
		margin-left: 0;
	}
	img, iframe {
		max-width: 100% !IMPORTANT;
	}
}

/* Hero Feature */
.row-hero {
	align-items: center;
}
.col-hero-img {
	text-align: center;
}
.col-hero-img img {
	margin: 0 auto;
}

/* Header/Hero Buttons */
#header-signup-btn,
#header-login-btn,
#hero-signup-btn,
#hero-contact-btn {
	display: block;
    line-height: 1.5em;
    padding: 5px 20px;
    color: #ffffff;
    margin: 0 0 3px;
}
#hero-signup-btn,
#hero-contact-btn {
	padding: 11px 25px;
	margin: 0 0 9px;
	font-weight: 500;
	font-size: 1.25em;
}
#header-signup-btn,
#hero-signup-btn {
	background: var(--theme-colour-main);
}
#header-login-btn,
#hero-contact-btn {
	background: var(--theme-colour-link-hover);
	margin: 0;
}

/* Main Menu */
nav.navbar {
	padding: 0;
	margin: 15px 0 0;
    min-height: 61px;
}
nav.navbar ul.nav-menu {
	list-style-type: none;
    margin: 0;
    padding: 0;
}
nav.navbar ul.nav-menu li {
	margin: 0;
    padding: 0;
	float: left;
	line-height: 1.35rem;
}
nav.navbar ul.nav-menu li a,
nav.navbar ul.nav-menu li a:link,
nav.navbar ul.nav-menu li a:visited {
	display: inline-block;
	padding: 10px;
	font-size: 1.25rem;
	text-decoration: none;
	font-weight: 500;
	color: var(--theme-colour-text);
	-webkit-transition: all 0.35s;
	-moz-transition: all 0.35s;
	transition: all 0.35s;
}
nav.navbar ul.nav-menu li a i {
	font-size: 16px;
}
nav.navbar ul.nav-menu li a:hover {
	color: var(--theme-colour-light-blue);
	-webkit-transition: all 0.25s;
	-moz-transition: all 0.25s;
	transition: all 0.25s;
}
nav.navbar ul.nav-menu li:first-child a {
	padding-left: 0;
}
nav.navbar ul.nav-menu li:last-child a {
	padding-right: 0;
}
nav.navbar ul.nav-menu li.has-child {}
nav.navbar ul.nav-menu li.has-child .child-wrapper {
	position: absolute;
	display: block;
	width: auto;
	opacity: 0;
	margin: 0 0 0 10px;
	padding: 5px 10px;
	border: 1px solid var(--theme-colour-main-light);
	background: #ffffff;
	z-index: -1;
	-webkit-box-shadow: 3px 3px 3px 0px rgba(0,0,0,0.33);
    -moz-box-shadow: 3px 3px 3px 0px rgba(0,0,0,0.33);
    box-shadow: 3px 3px 3px 0px rgba(0,0,0,0.33);
	-webkit-transition: all 0.35s;
	-moz-transition: all 0.35s;
	transition: all 0.35s;
}
nav.navbar ul.nav-menu li:first-child .child-wrapper {
	margin-left: 0;
}
nav.navbar ul.nav-menu li.has-child:hover > .child-wrapper {
	opacity: 1;
	z-index: 9999;
	-webkit-transition: all 0.45s;
	-moz-transition: all 0.45s;
	transition: all 0.45s;
}
nav.navbar ul.nav-menu li.has-child .child-wrapper ul.child-menu {
	list-style-type: none;
    margin: 0;
    padding: 0;
}
nav.navbar ul.nav-menu li.has-child .child-wrapper ul.child-menu li {
	margin: 0;
    padding: 0;
	float: none;
}
nav.navbar ul.nav-menu li.has-child .child-wrapper ul.child-menu li a,
nav.navbar ul.nav-menu li.has-child .child-wrapper ul.child-menu li a:link,
nav.navbar ul.nav-menu li.has-child .child-wrapper ul.child-menu li a:visited {
	margin: 0;
	padding: 5px 0;
	font-size: 1.15rem;
	color: var(--theme-colour-main);
}
nav.navbar ul.nav-menu li.has-child .child-wrapper ul.child-menu li a:hover {
	color: var(--theme-colour-link-hover);
}
.mobile-menu-close {
    position: fixed;
    top: 5px;
    right: -1000px;
	margin-right: 10px;
    font-size: 36px;
	color: var(--theme-colour-main);
    cursor: pointer;
	transition: right 0.35s;
	z-index: 99999;
}
@media screen and (max-width: 991px) {
	nav.navbar ul.nav-menu li a, 
	nav.navbar ul.nav-menu li a:link, 
	nav.navbar ul.nav-menu li a:visited {
		padding: 5px;
		font-size: 1rem;
	}
}
@media screen and (max-width: 414px) {
	/* Adjust Logo bottom margin */
	#nwm-tools-header img {
		margin-bottom: 15px;
	}
	
	/* Adjust menu to work with mobiles */
	nav.navbar {
		position: fixed;
		top: 0;
		right: -1000px;
		width: 100%;
		margin: 0 0 15px 0;
		padding: 15px;
		z-index: 99999;
		background: #fff;
		border-bottom: 1px solid var(--theme-colour-main);
		transition: right 0.35s;
		z-index: 99999;
	}
	nav.navbar ul.nav-menu li {
		display: block;
		float: none;
	}
	nav.navbar ul.nav-menu li a,
	nav.navbar ul.nav-menu li a:link,
	nav.navbar ul.nav-menu li a:visited {
		padding: 15px;
	}
	.mobile-menu-close {
		
	}
}
/* Mobile Menu */
.mobile-menu {
	margin-top: 15px;
    text-align: center;
}
.mobile-menu i {
	font-size: 36px;
	color: var(--theme-colour-main);
	cursor: pointer;
}
@media screen and (min-width: 415px) {
	.mobile-menu {
		display: none;
	}
}

/* Front Web Forms */
.app-front-form textarea {
	min-height: 80px;
}
.app-front-form .input-group button {
	height: 100%;
	font-weight: 700;
	font-size: 16px;
	color: #fff;
	background-color: var(--theme-colour-main);
}
.app-front-form .input-group button:hover {
	background-color: var(--theme-colour-link-hover);
	border-color: var(--theme-colour-link-hover);
	color: #fff;
}
.app-front-form .form-group button {
	font-weight: 700;
	font-size: 16px;
	color: #fff;
	background-color: var(--theme-colour-main);
}
.app-front-form .form-group button:hover {
	background-color: var(--theme-colour-link-hover);
	border-color: var(--theme-colour-link-hover);
	color: #fff;
}
.app-front-form .app-front-form-msg {
	height: 32px;
	max-height: 32px;
	margin-top: 5px;
}
.app-front-form .app-front-form-msg span.nwm-red {
	font-weight: bold;
	color: #cc0000;
}
.app-front-form .app-front-form-msg span.nwm-green {
	font-weight: bold;
	color: #008000;
}
.app-front-form .input-override {
	display: none;
}

/* Footer */
.container-footer,
.container-footer p,
.container-footer ul {
	color: #ffffff;
}
.container-footer a, .container-footer a:link, .container-footer a:visited, .container-footer a:focus {
	color: #ffffff;
	transition: color 0.35s;
}
.container-footer a:hover {
	color: var(--theme-colour-lighter-blue)!IMPORTANT;
	transition: color 0.25s;
}
#checkout {
    display: none;
    position: fixed;
    width: 94%;
    max-height: 80%;
    top: 5%;
    left: 3%;
    z-index: 99999;
    padding: 15px;
    overflow-y: auto;
    background: #000000;
    -webkit-box-shadow: 3px 3px 5px 0px rgba(0,0,0,0.66);
    -moz-box-shadow: 3px 3px 5px 0px rgba(0,0,0,0.66);
    box-shadow: 3px 3px 5px 0px rgba(0,0,0,0.66);
    border: 2px solid #3078db;
}
.btn-checkout {
    margin-top: 5px;
}
.powered-by-stripe svg {
    max-width: 160px;
    margin-top: 0;
}
@media screen and (min-width: 415px) {
    #checkout {
        width: 50%;
        top: 10%;
        left: 25%;
    }
}
@media screen and (min-width: 1024px) {
	#checkout {
        width: 33%;
        top: 10%;
        left: 33%;
        padding: 30px;
    }
}
@media screen and (max-width: 430px) {
	.footer div,
    .footer div ul li {
        display: block;
        width: 100%;
        text-align: center;
    }
    .footer div ul {
        margin-top: 10px;
    }
    .footer div ul li {
        padding: 5px 0;
    }
    .footer div ul li:last-child {
        padding: 15px 0 5px;
    }
}
.btn-success {
    color: #fff;
    background-color: #3078db!important;
    border-color: #3078db!important;
}
/* ===================================================================
   LOG IN AND SIGN UP -- ONE GREEN, ONE BLUE
   -------------------------------------------------------------------
   They were both green. Log In filled #2dc26b, Sign Up black with a
   white outline that turned #2dc26b on hover, so pointing at either one
   produced the same green button and the pair had no hierarchy at all
   -- it just had a delay before it lost its hierarchy.

   Green is GO and price, and only that. Two greens in one corner spend
   the one colour that is supposed to mean something. So Log In keeps
   the green, which is what Martin asked for this morning, and Sign Up
   takes the app's blue.

   THE BLUE IS NOT A NEW COLOUR. It is the treatment the hamburger on
   the other side of this bar already uses and the app uses for every
   secondary control: an outline at rest -- rgba(91,147,255,.55) on
   #5b93ff text -- filling to #2563eb when you commit to it. Whatever
   else changes, the public bar now speaks the app's language for "this
   is the quiet one".

   NOT chosen from the ribbons. The obvious story was that the blue slab
   sits over Log In and the green over Sign Up, so the buttons should
   match the slab above them -- but the slabs CROSSFADE and swap sides.
   Sampled over ten seconds: path A ran green while B ran blue, and a
   minute earlier it was the other way round. An argument from adjacency
   would have been wrong within the minute.

   THE HOVER DOES SOMETHING NOW. It was a flat colour swap, which on the
   outlined button meant the border simply changed colour. Both buttons
   lift 1px and cast a shadow in their own hue, so the feedback is the
   button coming toward you rather than repainting. :focus-visible gets
   the same ring, because a keyboard should not be the one state with no
   answer. Motion is dropped for anyone who asked for it to be.
   =================================================================== */
.btn-public-signup,
.btn-public-login {
    border-radius: 15px!important;
    padding: 3px 18px!important;
}
/* THE TRANSITION NEEDS THE LONGER SELECTOR, and the colours above do not,
   because they carry !important and this does not. These buttons are <a>
   elements, and the theme has `a, a:link, a:visited, a:focus { transition:
   color .35s }`. `a:link` is (0,1,1); a bare `.btn-public-login` is
   (0,1,0) and loses -- so the first version of this animated nothing but
   the text colour, and only the transition, silently. Measured, not
   spotted: transition-property computed as `color`. */
.top-button-menu a.btn-public-signup,
.top-button-menu a.btn-public-login {
    transition: background-color .16s ease, border-color .16s ease,
                color .16s ease, transform .16s ease, box-shadow .16s ease;
}
/* Log In -- outlined at rest like Sign Up, and it fills from a rotating
   sweep rather than by swapping colour. Both buttons now start as
   outlines, so the difference between them is what happens when you
   reach for them, which is the only moment the difference matters.

   The fill is NOT a background transition on the button. It is an
   ::after that goes green on a delay, sitting over an ::before that
   carries the spinning gradient -- so the sweep runs first and is then
   covered by the green it was promising. A background transition cannot
   do that, because there is only one background. */
.btn-public-login {
    background: transparent!important;
    border: 2px solid rgba(45,194,107,.55)!important;
    color: #2dc26b!important;
}
.btn-public-login:hover,
.btn-public-login:focus-visible {
    border-color: #2dc26b!important;
    color: #fff!important;
    transform: translateY(-1px);
    box-shadow: 0 6px 16px rgba(45,194,107,.34);
}
/* Sign Up -- outlined, the blue one. */
.btn-public-signup {
    background: transparent!important;
    border: 2px solid rgba(91,147,255,.55)!important;
    color: #5b93ff!important;
}
.btn-public-signup:hover,
.btn-public-signup:focus-visible {
    background: #2563eb!important;
    border-color: #2563eb!important;
    color: #fff!important;
    transform: translateY(-1px);
    box-shadow: 0 6px 16px rgba(37,99,235,.38);
}
/* Pressed goes back down. A lift that stays lifted while the mouse is
   held is the one part of this that would read as broken. */
.btn-public-login:active,
.btn-public-signup:active {
    transform: translateY(0);
    box-shadow: none;
}

/* ---- THE ROTATING SWEEP ON LOG IN --------------------------------
   Scoped to the bar. The same two classes are on links in the flyout
   menu, where the button skin is deliberately stripped further down
   this file -- but nothing there resets a pseudo-element, so an
   unscoped ::before would have a conic gradient spinning behind a
   plain menu row on hover.

   HOW IT IS BUILT, since none of it is obvious from the declarations:

   ::before is a 200px SQUARE, centred, carrying the conic gradient. It
   is square because a rotating rectangle sweeps its own corners through
   the frame and the light pulses as it turns; a square rotating about
   its centre presents the same silhouette at every angle. 200 clears
   the pill's ~88px diagonal, so no corner ever enters the view.

   It is the ELEMENT that rotates, not the gradient's `from` angle.
   Animating an angle inside conic-gradient needs @property to be
   interpolable at all, and where that is unsupported it does not
   degrade -- it simply never moves. A transform rotation runs
   everywhere and on the compositor.

   overflow:hidden clips it to the pill. That clips to the PADDING box,
   inside the border, so the sweep runs within the outline rather than
   around it and the green rim stays a rim throughout.

   ::after is the fill, on a .25s delay -- long enough for about a
   quarter turn to read before the green covers it. The label sits above
   both on z-index 2, and takes the same delay so the text turns white
   as the green arrives underneath it rather than a beat early against
   nothing. -------------------------------------------------------- */
.top-button-menu a.btn-public-login {
    position: relative;
    overflow: hidden;
    transition: border-color .16s ease, transform .16s ease,
                box-shadow .16s ease, color .3s ease .25s;
}
.top-button-menu a.btn-public-login > i,
.top-button-menu a.btn-public-login > span {
    position: relative;
    z-index: 2;
}
.top-button-menu a.btn-public-login::before {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 200px;
    height: 200px;
    margin: -100px 0 0 -100px;
    z-index: 0;
    opacity: 0;
    background: conic-gradient(from 0deg,
        rgba(122,240,170,0) 0deg,
        rgba(122,240,170,.9) 60deg,
        rgba(190,255,220,1) 105deg,
        rgba(122,240,170,.9) 150deg,
        rgba(122,240,170,0) 240deg,
        rgba(122,240,170,0) 360deg);
    transition: opacity .16s ease;
}
.top-button-menu a.btn-public-login::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    background-color: rgba(45,194,107,0);
    transition: background-color .3s ease .25s;
}
.top-button-menu a.btn-public-login:hover::before,
.top-button-menu a.btn-public-login:focus-visible::before {
    opacity: 1;
    animation: lhq-login-sweep .9s linear infinite;
}
.top-button-menu a.btn-public-login:hover::after,
.top-button-menu a.btn-public-login:focus-visible::after {
    background-color: #2dc26b;
}
@keyframes lhq-login-sweep {
    to { transform: rotate(360deg); }
}
/* Reduced motion keeps the outline-to-fill, which is the information,
   and drops the spinning, which is the flourish. The fill loses its
   delay too -- a quarter-second of nothing happening only makes sense
   while something is happening in it. */
@media (prefers-reduced-motion: reduce) {
    .top-button-menu a.btn-public-login {
        transition: border-color .16s ease, color .16s ease;
    }
    .top-button-menu a.btn-public-login:hover::before,
    .top-button-menu a.btn-public-login:focus-visible::before {
        opacity: 0;
        animation: none;
    }
    .top-button-menu a.btn-public-login::after {
        transition: background-color .16s ease;
    }
}
@media (prefers-reduced-motion: reduce) {
    .top-button-menu a.btn-public-signup,
    .top-button-menu a.btn-public-login {
        transition: background-color .16s ease, border-color .16s ease, color .16s ease;
    }
    .btn-public-login:hover,
    .btn-public-login:focus-visible,
    .btn-public-signup:hover,
    .btn-public-signup:focus-visible {
        transform: none;
    }
}
.btn-back,
.btn-subscribe,
.btn-purchase-digital,
.btn-join-login {
    background-color: rgb(52, 199, 89)!important;
    color: rgb(255, 255, 255)!important;
    border-color: rgb(52, 199, 89)!important;
}
.btn-back:hover,
.btn-subscribe:hover,
.btn-purchase-digital:hover,
.btn-join-login:hover {
    background-color: rgb(97, 97, 97)!important;
    color: rgb(255, 255, 255)!important;
    border-color: rgb(97, 97, 97)!important;
}
.input-group-addon {
    color: #fff!important;
    background: #3078db!important;
    border-radius: 0!important;
}
.input-group-addon-help {
    background: #28a72c!important;
}
.popover-title {
    background-color: #3078db!important;
    color: #fff;
    font-weight: 500;
}
.row.row-public {
    display: flex;
    width: 100%;
    margin-left: 0;
    background: #3d3d3d;
    align-items: center;
}
/* THE PHONE GUTTER WAS 35px A SIDE, on a 375px screen -- 19% of the
   display spent on margin. Two wrappers stack it: .container-content
   pads 20 and Bootstrap's .col-md-12 pads another 15, and neither was
   written with a phone in mind. Measured on a 375 viewport: the grid
   had 255px to draw in and sat off-centre, because the 10px the
   scrollbar takes comes off one side only.

   16 a side is the figure, which is the ordinary phone gutter and what
   the cards were designed against. Scoped to the marketplace rather
   than applied to every public page, because the landing pages and the
   storefront have their own layouts and are not what is being looked
   at -- they are worth the same measurement, separately. */
/* .container-content-full's padding MOVED TO brand.css. It was here, and
   here is wrong: public.css is only in the public bundle, so the rule
   covered a signed-out visitor and silently left a signed-in one with no
   padding at all -- the wrapper's 20px had been an inline style that
   applied in both. brand.css is one of the two sheets both bundles load.
   The full note is there. */

/* THE BAR STOPS BEING A BAR, so the plate can be a layer on top of it.
   chrome.css paints `.navbar-static-top, .footer` #003142 -- one rule for
   both -- and the plate is #0f3d4a. Two teals a few units apart, so the
   thing that is supposed to be sitting ON the page read as part of a
   strip instead, and the drop shadow under it had nothing to fall on.

   Page colour instead. Every public page's body is #1d1d1d -- checked on
   /, /contact-us/ and /products/, where the sections over it are all
   transparent -- so one value works everywhere and the bar simply stops
   being visible. What is left is a logo and a plate floating on the page,
   which is what the signed-in chrome looks like.

   OPAQUE, NOT TRANSPARENT, and that is the whole reason a band is still
   here. The nav is position:fixed and content scrolls underneath it; make
   it transparent and product cards travel up through the logo. Matching
   the page gets the look without the collision.

   Scoped to .row-public so the admin bar and the footer, which share that
   chrome.css rule, keep their own colour. */
.row-public nav.navbar-static-top {
    background-color: #1d1d1d;
}
body.courses .row.row-public {
    margin-bottom: 15px;
}
nav.navbar {
    padding: 0;
    margin: 0;
}
.top-student-menu {
    display: inline-block!important;
    margin-left: 15px;
}
/* #35c95b LIVED HERE -- a THIRD green, and the one the earlier sweep walked
   past because it was hunting #00bf63, #00d16d and rgb(0,191,99). Three
   greens for one button across one stylesheet.

   It is gone rather than corrected: the full rule further down this file now
   owns this button in both its states, and a second declaration that happens
   to lose on source order is a trap for whoever next moves a block. */
.student-menu-flyout {
    margin-top: 0;
}
body.courses .student-menu-flyout {
    margin-top: -15px;
}
body.public .student-menu-flyout .nav-label {
    display: block!important;
}
.student-menu-flyout li.standard-menu-item:hover {
    border-left: 5px solid #2f77db;
    background: #2f77db;
}
.student-menu-flyout li.standard-menu-item:hover > a {
    color: #ffff !important;
}
/* ===================================================================
   THE PUBLIC CLUSTER, BUILT AS THE SIGNED-IN BAR'S PLATE
   -------------------------------------------------------------------
   The signed-in chrome puts the store picker, the two animated slabs
   and the icon cluster on one angled teal plate in the top right
   corner. This is that plate with Log In and Sign Up in the outer two
   slots, so a visitor and a creator are looking at the same object.

   THE NUMBERS ARE NOT RE-CHOSEN. They are v2.css's, which are
   appShellChrome.html's, which were swept rather than picked:
   --rib-gap 37 is the distance at which the pair -- measured across
   every mode, pose and blend, 3.9M states -- still clears what sits
   beside it, and --rib-span 66.9 is the width the pair actually
   paints on average rather than the 91 it could theoretically reach.
   Reserving the maximum leaves a hole the eye reads as bad spacing.
   Re-derive them there, not here, if the artwork ever changes.

   They are declared ON THE CLUSTER rather than on :root because
   v2.css does not load on a public page and :root here would put six
   chrome variables into every landing page a creator builds.
   =================================================================== */
.top-button-menu {
    --pub-bar-h: 50px;
    --pub-pad: 22px;
    --pub-cut: 14px;      /* 50 x tan(16deg), so the cut stays parallel
                             to the slabs -- change one, change both */
    --rib-gap: 37px;
    --rib-span: 66.9;
    --rib-reach: 0;

    position: relative;
    display: flex;
    align-items: center;
    gap: var(--rib-gap);
    height: var(--pub-bar-h);
    /* nav.navbar is a fixed 65px flex row that does NOT centre its
       children -- they stretch from the top. The old margin-top:16px was
       doing this by hand for two 30px buttons; a 50px plate needs the
       real thing, or it sits flush to the top with 15px of bar under it. */
    align-self: center;
    margin-left: auto;
    margin-right: 0;
    margin-top: 0;
    padding: 0 var(--pub-pad) 0 calc(var(--pub-pad) + var(--pub-cut) / 2);
}
/* The old rule. A flex `gap` owns the spacing now, and a margin-right
   on the last child would push Sign Up off the plate's padding. */
.top-button-menu a {
    margin-right: 0;
}
/* Rounded on the leading edge only -- the trailing edge runs to the
   screen edge, so rounding it would be a corner nobody can see doing
   the opposite of what the shape says. Lifted from .sh-plate. */
.pub-plate {
    position: absolute;
    inset: 0;
    z-index: 1;
    border-radius: 5px 0 0 5px;
    clip-path: polygon(var(--pub-cut) 0, 100% 0, 100% 100%, 0 100%);
    background: linear-gradient(97deg, #0f3d4a 0%, #0c3340 46%, #0a2733 100%);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.07), 0 10px 28px rgba(0,0,0,.45);
}
/* The slot is a real flex item with no height, so the gaps either side
   of the slabs are measurable. The slabs themselves are 222x225 turned
   16deg and hang well outside it -- that is the point, they bleed below
   the bar -- so nothing here may clip. */
.top-button-menu .sh-ribwrap {
    position: relative;
    flex: none;
    height: 0;
    z-index: 2;
    pointer-events: none;
    width: calc((var(--rib-span) + 2 * var(--rib-reach)) * 1px);
}
/* 164deg is 180 minus the 16 the element is turned by, so the fade
   arrives on the page pointing straight down and both slabs end on the
   same line. Turning it any other way staggers them by about 14px and
   reads as one slab hanging below the other. */
.top-button-menu .sh-rib {
    position: absolute;
    top: 0;
    left: 50%;
    margin-left: -111px;
    width: 222px;
    height: 225px;
    transform: translateY(-50%) rotate(16deg);
    transform-origin: 50% 50%;
    -webkit-mask-image: linear-gradient(164deg, #000 0, #000 50%, rgba(0,0,0,.3) 66.9%, transparent 74.5%);
    mask-image: linear-gradient(164deg, #000 0, #000 50%, rgba(0,0,0,.3) 66.9%, transparent 74.5%);
}
.top-button-menu .sh-rib svg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}
/* Everything anyone actually presses sits above the slabs. */
.top-button-menu .btn-public-login,
.top-button-menu .btn-public-signup {
    position: relative;
    z-index: 4;
    flex: none;
}
/* Too narrow for the cluster to carry everything. The ribbons go first
   because they are the decoration -- and 1060 is not a number picked
   here, it is the one v2.css drops .sh-ribwrap at, for that same reason.
   The two bars should not disagree about when the artwork stops fitting.

   The engine keeps drawing into the hidden slot below this width, which
   is what the signed-in bar does too. Matching it is deliberate: a
   second, cleverer behaviour out here is a second thing to keep in step.
   If it is ever worth stopping, stop it in both. */
@media (max-width: 1060px) {
    .top-button-menu .sh-ribwrap {
        display: none;
    }
    .top-button-menu {
        gap: 14px;
    }
}
/* ===================================================================
   THE PHONE BAR IS THE SAME OBJECT SIGNED IN OR OUT
   -------------------------------------------------------------------
   780 is the app's breakpoint, not a new one: it is where the signed-in
   plate stops being a plate and becomes a full-width bar with a burger
   on the left, the mark in the middle and one control on the right.
   Seen side by side on a phone, the signed-out bar was the odd one out
   -- no burger, no background, and two pills where the other had one
   icon. Three differences for a visitor who is about to become one of
   the other two.

   So it is the same bar. The plate goes, the teal comes back, the
   burger returns, and Sign Up steps out of the bar into the flyout,
   which has carried it all along -- Home, Sign Up, Log In, Contact Us.
   Log In stays as the single icon on the right, where the signed-in bar
   puts the way out.

   THE BURGER NEEDS THE !important AND THE LONGER SELECTOR. Signed out
   it carries .bar-menu-hidden, which is itself `display:none
   !important` -- it has to be, because three separate rules in this
   file set this element's display that way. Undoing it takes the same
   weight plus one more class.
   =================================================================== */
@media (max-width: 780px) {
    .row-public nav.navbar-static-top {
        background-color: #003142;
    }
    /* .row-public IN FRONT, and it is load-bearing. The rule that hides
       this signed out is `.top-student-menu.bar-menu-hidden` -- the same
       two classes -- and it sits ~1200 lines further down this file. A
       media query adds NO specificity, so an identical selector inside
       one still loses on source order, and the first version of this
       changed nothing at all. One more ancestor class settles it without
       moving either block. */
    .row-public .top-student-menu.bar-menu-hidden {
        display: inline-flex !important;
    }
    /* AND IT LOOKS LIKE THE SIGNED-IN ONE HERE. On the wide bar this
       button is an outlined blue chip that fills when the menu opens --
       Martin asked for that, and it is the app's secondary-control
       language. The signed-in PHONE bar's burger is a plain glyph, so
       at this width the outline is the one thing still telling you
       which of the two bars you are on. It goes.

       The desktop rule is untouched: this is scoped to the phone, which
       is where "the same bar" was the ask. The open state still reads,
       because the flyout it opens covers most of the screen. */
    .row-public .top-student-menu .student-nav,
    body.menu-open .row-public .top-student-menu .student-nav {
        background-color: transparent !important;
        border: 0 !important;
        color: #98a1ad !important;
        width: 38px;
        height: 38px;
        padding: 0 !important;
        border-radius: 9px !important;
    }
    body.menu-open .row-public .top-student-menu .student-nav {
        color: #e9edf2 !important;
        background-color: rgba(255,255,255,.08) !important;
    }
    .top-button-menu {
        height: auto;
        padding: 0;
        gap: 0;
    }
    .pub-plate {
        display: none;
    }
    /* In the flyout, not gone: a visitor who wants to sign up is the
       point of the page, and the flyout is one press away. Two pills in
       a 375px bar is what crowded the mark. */
    .top-button-menu .btn-public-signup {
        display: none !important;
    }
    /* The one control, sized and shaped like the signed-in bar's exit
       icon rather than like a pill that lost its label. */
    .top-button-menu > a.btn-public-login {
        display: inline-flex !important;
        align-items: center;
        justify-content: center;
        width: 40px;
        height: 40px;
        margin: 0 !important;
        padding: 0 !important;
        background: none !important;
        border: 0 !important;
        border-radius: 9px !important;
        color: #2dc26b !important;
    }
    .top-button-menu > a.btn-public-login i {
        margin: 0;
        font-size: 18px;
        color: #2dc26b !important;
    }
    .top-button-menu > a.btn-public-login span {
        display: none;
    }
    /* The sweep has no outline to run inside once the button is a bare
       glyph, and there is no hover on a phone to start it -- it could
       only ever fire as a flash on tap. */
    .top-button-menu > a.btn-public-login::before,
    .top-button-menu > a.btn-public-login::after {
        display: none;
    }
}
/* The storefront's search box and its phone magnifier stood here, with the same
   hidden-by-default pair chrome.css carried. Both are gone -- the search reached
   /offers/, which is the marketplace, and that is being held back for now. See
   top_bar.tpl for the full note. The width rules the media blocks below kept
   re-tuning for it (1079, 979, 579, 429) went at the same time, and so did the
   two rules at 500 and 419 that first showed the magnifier and then hid it again
   on a narrow bar. */
.footer {
    position: relative;
    bottom: auto;
    left: auto;
    right: auto;
}
.container-footer {}
.container-footer .row {
    border-top: 1px solid #fff!important;
}
.hero-container {
    margin-top: -15px;
    margin-bottom: 30px;
    background-size: cover;
    background-position: center;
}
.hero-container .hero-col {
    padding-top: 100px;
    padding-bottom: 100px;
}
.hero-h1 {
    margin: 0;
    color: #fff;
    text-align: center;
    font-size: 48px; 
    line-height: 1.45;
}
@media (max-width: 1179px) {
    .btn-public-signup,
    .btn-public-login {
        padding: 3px 6px!important;
    }
}
@media (max-width: 879px) {
    .hero-container .hero-col {
        padding-top: 90px;
        padding-bottom: 90px;
    }
    .hero-h1 {
        font-size: 40px; 
    }
}
@media (max-width: 679px) {
    .hero-container .hero-col {
        padding-top: 70px;
        padding-bottom: 70px;
    }
    .hero-h1 {
        font-size: 36px; 
    }
}
@media (max-width: 579px) {
    .btn-public-signup,
    .btn-public-login {
        padding: 2px 4px!important;
        font-size: 12px!important;
    }
    .top-student-menu {
        margin-top: 8px;
        margin-right: 12px;
        padding: 3px 6px!important;
    }
    .hero-container .hero-col {
        padding-top: 60px;
        padding-bottom: 60px;
    }
    .hero-h1 {
        font-size: 32px; 
    }
}
@media (max-width: 429px) {
    nav.navbar {
        position: relative;
        right: auto;
        background: none;
        border-bottom: none;
    }
    .top-student-menu {
        margin-right: 5px;
        margin-left: 5px;
    }
    .hero-container .hero-col {
        padding-top: 40px;
        padding-bottom: 40px;
    }
    .hero-h1 {
        font-size: 28px; 
        line-height: 1.35;
    }
}
.btn-public-login i,
.btn-public-signup i {
    display: none;
}
.btn-public-login i {
    font-size: 16px;
    color: #18bf18;
}
@media (max-width: 500px) {
    .img-logo-a {
        display: inline-block!important;
        margin-top: 8px!important;
        margin-left: -4px!important;
    }
    .top-button-menu {
        margin-top: 18px;
    }
    .btn-public-login,
    .btn-public-signup {
        background: none!important;
        border: none!important;
    }
    .btn-public-login i,
    .btn-public-signup i {
        display: inline-block;
    }
    .btn-public-login span,
    .btn-public-signup span {
        display: none;
    }
}
@media (max-width: 379px) {
    nav.navbar {
        background: #000;
    }
    .img-logo-a {
        width: 200px;
        margin-top: 6px!important;
        margin-left: -15px!important;
    }
}
.signup-form-modal {
    text-align: center;
}
/* THE AUTH PANEL. Was pure #000 with a 3px radius and a z-index of 2,
   floating over the page with nothing behind it to say the page had stopped
   -- so it read as a box that had landed on the hero rather than as a thing
   asking for your attention.

   #242424 and a hairline is the panel surface the rest of the product uses;
   14px is the radius the marketplace cards use. z-index is raised because 2
   is below almost anything, and a login form that something else can cover
   is a login form that sometimes cannot be filled in.

   NO SCRIM HERE. There is already a .public-forms-overlay in
   footer_public.tpl and public.js already closes the panel when it is
   clicked. A ::before on this element was tried and was a bad idea: it
   painted over that overlay and swallowed the clicks, leaving a modal with
   no button, no Escape and no click-out -- unclosable. See the note on
   .public-forms-overlay further down. */
#public-login-wrapper,
#public-signup-wrapper,
#public-signup-login-wrapper {
   display: none;
   position: fixed;
   top: 50%;
   left: 50%;
   transform: translate(-50%, -50%);
   width: 400px;
   max-width: calc(100vw - 32px);
   max-height: calc(100vh - 48px);
   overflow-y: auto;
   padding: 26px 24px 24px;
   background: #242424;
   border: 1px solid rgba(255,255,255,.09);
   color: #e9edf2;
   text-align: center;
   border-radius: 14px;
   box-shadow: 0 24px 60px rgba(0,0,0,.6);
   z-index: 1200;
}
/* The combined one is taller because it carries both forms. It no longer
   forces height:80% and overflow:scroll -- which drew a scrollbar on a panel
   that did not need one -- because max-height and overflow-y:auto above
   already do it, and only when there is something to scroll. */
#public-signup-login-wrapper {
    width: 420px;
}
#public-login-wrapper h3,
#public-signup-wrapper h3,
#public-signup-login-wrapper h3 {
    width: 100%;
    color: #ffffff;
    font-size: 18px;
    text-align: center;
}
#public-login-wrapper p,
#public-signup-wrapper p,
#public-signup-login-wrapper p {
    color: #f1f1f1;
}
#public-login-wrapper .actions .btn,
#public-signup-wrapper .actions .btn,
#public-signup-login-wrapper .actions .btn {
    margin-right: 0!important;
}
#public-login-wrapper .btn-success {
    margin-bottom: 10px;
    padding: 6px 36px;
    font-weight: 700;
    font-size: 16px;
    border-radius: 4px!important;
}
#submit-login-modal, 
#submit-login-modal-2 {
    background: #18bf18!important;
    border: 1px solid #18bf18!important;
    border-radius: 15px!important;
}
/* .btn-public-signup IS NO LONGER IN THESE TWO SELECTORS, and taking it
   out is the whole reason the skin above works. This block is later in
   the file, so its `background:#000!important` beat the rule that owns
   the button 500 lines up -- the same trap the note in the phone block
   at the foot of this file describes, still set, still catching things.
   One button, one place, and that place is the block above.

   .btn-public-signup-2 is left because removing it is not this change,
   but it appears in no template, no module and no script -- it looks
   like dead CSS and is worth deleting once someone has checked. */
.btn-public-signup-2 {
    background: #000!important;
    border: 2px solid #fff!important;
    border-radius: 15px!important;
}
#submit-login-modal:hover,
#submit-login-modal-2:hover,
.btn-public-signup-2:hover {
    opacity: 0.85;
}
/* THE SCRIM WAS ALREADY HERE, and public.js already closes the panel when
   you click it. Raising the panel to z-index 1200 without raising this left
   the scrim underneath the page it was meant to cover -- and briefly I
   "fixed" that by adding a ::before to the panel, which painted over this
   element and swallowed the clicks that dismiss it. The modal became
   impossible to close by any means: no button, no Escape, no click-out.

   Styling the element that exists is the fix. It keeps its handler, and
   1199 puts it under the panel and over everything else. */
/* A WAY OUT OF EVERY WINDOW (14 Oct 2026, Martin: "a way for people to also just close
   down the modal even if they dont want to create an account"). The dimmed area closed
   them, but nothing said so, and over Try Merlin's full-screen editor it read as part of
   the window. A close button in the corner of each, and Escape (public.js). */
#public-login-wrapper .pfm-close,
#public-signup-wrapper .pfm-close,
#public-signup-login-wrapper .pfm-close {
   position: absolute;
   top: 10px;
   right: 10px;
   width: 34px;
   height: 34px;
   padding: 0;
   border: 0;
   border-radius: 8px;
   background: transparent;
   color: #98a1ad;
   font-size: 24px;
   line-height: 34px;
   text-align: center;
   cursor: pointer;
   z-index: 1;
}
#public-login-wrapper .pfm-close:hover,
#public-signup-wrapper .pfm-close:hover,
#public-signup-login-wrapper .pfm-close:hover {
   background: rgba(255,255,255,.08);
   color: #e9edf2;
}
#public-login-wrapper .pfm-close:focus-visible,
#public-signup-wrapper .pfm-close:focus-visible,
#public-signup-login-wrapper .pfm-close:focus-visible {
   outline: 2px solid #2563eb;
   outline-offset: 2px;
}
.public-forms-overlay {
    display: none;
    width: 100%;
    height: 100%;
    background: rgba(8,10,12,.66);
    backdrop-filter: blur(3px);
    position: fixed;
    top: 0;
    left: 0;
    margin: 0;
    z-index: 1199;
    cursor: pointer;
}
#js-msg-login-modal,
#js-msg-login-modal-2,
#js-msg-signup-modal,
#js-msg-signup-modal-2 {
    display: none;
}
@media (max-width: 472px) {
    html {
        overflow-x: hidden;
    }
    /* CENTRED ONCE (16 Oct 2026). This said left: calc(50% - 172px), centring
       by hand, and the rule above now centres with translate(-50%) as well:
       on a phone the window was moved left twice and sat half off the screen.
       It keeps left:50% from above and only takes the screen's width, padding
       included, so 16px shows either side. */
    #public-login-wrapper,
    #public-signup-wrapper,
    #public-signup-login-wrapper {
       box-sizing: border-box;
       width: calc(100vw - 32px);
    }
}
#public-welcome-modal {
   display: none;
   position: fixed;
   top: calc(50% - 215px);
   left: calc(50% - 200px);
   width: 400px;
   height: 430px;
   padding: 15px;
   background: #000;
   color: #f1f1f1;
   -webkit-border-radius: 3px;
   -moz-border-radius: 3px;
   border-radius: 3px;
   -webkit-box-shadow: 0px 3px 5px 1px rgba(0,0,0,0.33);
   -moz-box-shadow: 0px 3px 5px 1px rgba(0,0,0,0.33);
   box-shadow: 0px 3px 5px 1px rgba(0,0,0,0.33);
   z-index: 2;
}
#public-welcome-modal h3 {
    text-align: center;
    margin-bottom: 30px;
}
#public-welcome-modal ol li {
    padding-bottom: 10px;
}
#public-welcome-modal-buttons {
    text-align: center;
}
@media (max-width: 472px) {
    #public-welcome-modal {
        top: calc(50% - 240px);
        left: calc(50% - 150px);
        width: 300px;
        height: 480px;
    }
}

.modal-form-toggle {
    background: #000;
    border: 1px solid #fff;
    border-radius: 5px;
    stroke: none;
}
.modal-form-toggle.modal-form-toggle-active,
.modal-form-toggle:hover {
    background: #18bf18;
    border: 1px solid #18bf18;
}
#signup-form-modal-2 {
    display: none;
}

/* WHAT A CUSTOMER ACCOUNT LEAVES OUT (16 Oct 2026, Martin), shown only while
   CUSTOMER is picked (public.js). A div, not a p: p here is line-height 2. */
.signup-cust-note {
    margin: -4px 0 14px;
    padding: 9px 12px;
    border-radius: 10px;
    background: rgba(255,255,255,.05);
    color: #b8c0ca;
    font-size: 13px;
    line-height: 1.45;
    text-align: left;
}
.toggle-btn-wrapper {
    display: flex;
    align-items: stretch;
    gap: 10px;
}
/* The gap used to be an empty <div> </div> between the two buttons, padded
   0 10px. It is a flex container, so `gap` does the same job without a
   third child -- and the spacer only existed in one of the two panels, so
   the combined one had the buttons touching. */
/* CUSTOMER / CREATOR, as a segmented control rather than two buttons.
   19px was larger than the heading above it, and two heavily outlined pills
   read as two calls to action when only one of them is a choice you are
   making about yourself.

   #17addc is gone. It was the only colour on this panel in no palette this
   company has -- brandGuide lists exactly this kind of near-miss under open
   conflicts -- and the toggle disagreed with the submit button it sets the
   colour of. Both now take --theme-colour-main, so a theme change moves them
   together instead of leaving one behind.

   HOVER IS NOT SELECTION. The old rule painted :hover the same as .active,
   so pointing at CREATOR made it look chosen while CUSTOMER still was.

   EACH SEGMENT SAYS WHAT IT MEANS. The heading above used to read "Are you
   a CUSTOMER or a CREATOR?", which named the two buttons directly beneath
   it and so said everything twice -- and it spent the panel's only heading
   on the question, leaving the signup panel with no title at all while the
   login panel had one.

   The heading is now the title. The choice explains itself instead, because
   a segmented control with one segment already filled reads as a state
   rather than a question: the risk is not that nobody knows what the words
   mean, it is that nobody notices CUSTOMER was a choice they could change,
   fills the form and gets the wrong kind of account. A second line under
   each label makes it a question again without a sentence above it.

   "I'm buying" / "I'm selling" is vocabulary.md's own definition of the two
   words, so the hint teaches the word rather than replacing it -- Creator
   means nothing to someone who has never been here before. */
.modal-form-account-toggle {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    flex-grow: 1;
    width: 40%;
    margin-bottom: 15px;
    padding: 9px 0;
    background: transparent!important;
    border: 1px solid rgba(255,255,255,.14);
    border-radius: 10px;
    stroke: none;
    color: #98a1ad!important;
    font-size: 14px;
    font-weight: 700;
    letter-spacing: .04em;
    transition: background-color .14s, color .14s, border-color .14s;
}
.modal-form-account-toggle:hover {
    color: #e9edf2!important;
    border-color: rgba(255,255,255,.3);
}
.modal-form-account-toggle .toggle-label {
    font-size: 14px;
    font-weight: 700;
    letter-spacing: .04em;
    line-height: 1.1;
}
/* The hint is deliberately quiet and deliberately not italic: it is a
   definition, not an aside. It stays legible on the filled segment, where
   the background is --theme-colour-main or #2dc26b rather than the panel. */
.modal-form-account-toggle .toggle-hint {
    font-size: 11px;
    font-weight: 400;
    letter-spacing: 0;
    line-height: 1.1;
    opacity: .72;
    text-transform: none;
}
.modal-form-account-toggle.modal-form-account-toggle-active {
    background: var(--theme-colour-main)!important;
    border: 1px solid var(--theme-colour-main)!important;
    color: #fff!important;
}
/* Creator keeps its own colour, which is the one thing the old design got
   right: the two account types are a real fork and reading as different is
   the point. Hover dropped here too -- see the note above. */
#modal-form-account-toggle-creator.modal-form-account-toggle-active,
#modal-form-account-toggle-creator-2.modal-form-account-toggle-active {
    background: #2dc26b!important;
    border: 1px solid #2dc26b!important;
    color: #fff!important;
}
/* ===================================================================
   THE AUTH PANEL'S FIELDS AND BUTTONS
   -------------------------------------------------------------------
   The inputs were Bootstrap's: WHITE, with grey borders, on a black
   panel. That single thing did more to make this look unfinished than
   any colour on it -- five white slabs stacked down the middle of a
   dark page.

   Scoped to the three wrappers rather than to .app-input, which is used
   on public forms all over the site and is not ours to restyle from
   here.
   =================================================================== */
#public-login-wrapper .form-control,
#public-signup-wrapper .form-control,
#public-signup-login-wrapper .form-control {
    height: 42px;
    padding: 10px 13px;
    background: #1c1c1c;
    border: 1px solid rgba(255,255,255,.12);
    border-radius: 10px;
    color: #e9edf2;
    font-size: 14.5px;
    box-shadow: none;
    transition: border-color .14s, box-shadow .14s;
    /* As wide as the button under it (2 Oct 2026). Bootstrap's .form-control
       width is not loaded on public pages, so these were a browser's default
       177px, sitting centred above a full-width button. */
    display: block;
    width: 100%;
    box-sizing: border-box;
}
#public-login-wrapper .form-control::placeholder,
#public-signup-wrapper .form-control::placeholder,
#public-signup-login-wrapper .form-control::placeholder {
    color: #6f7885;
}
#public-login-wrapper .form-control:focus,
#public-signup-wrapper .form-control:focus,
#public-signup-login-wrapper .form-control:focus {
    outline: none;
    border-color: var(--theme-colour-main);
    box-shadow: 0 0 0 3px rgba(59,130,246,.22);
}
/* The form groups were separated by <br> in the markup, which cannot be
   tuned. A margin does the same job and can be. */
#public-login-wrapper .form-group,
#public-signup-wrapper .form-group,
#public-signup-login-wrapper .form-group {
    margin-bottom: 10px;
}
#public-login-wrapper br,
#public-signup-wrapper br,
#public-signup-login-wrapper br {
    display: none;
}

/* "Or" was a bare word floating between the Google button and the fields.
   A rule either side makes it a divider, which is what it was trying to be. */
#public-login-wrapper .google_login_or,
#public-signup-wrapper .google_login_or,
#public-signup-login-wrapper .google_login_or {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 16px 0;
    color: #6f7885;
    font-size: 12px;
    letter-spacing: .1em;
    text-transform: uppercase;
}
#public-login-wrapper .google_login_or::before,
#public-signup-wrapper .google_login_or::before,
#public-signup-login-wrapper .google_login_or::after,
#public-login-wrapper .google_login_or::after,
#public-signup-wrapper .google_login_or::after,
#public-signup-login-wrapper .google_login_or::before {
    content: "";
    flex: 1;
    height: 1px;
    background: rgba(255,255,255,.1);
}

/* The heading, which was 18px and the same weight as everything else. */
#public-login-wrapper h3,
#public-signup-wrapper h3,
#public-signup-login-wrapper h3 {
    font-size: 19px!important;
    font-weight: 900;
    letter-spacing: -.01em;
    margin: 0 0 16px;
}

/* THE LOGO'S GREEN, NOT BOOTSTRAP'S. The Login button carries .btn-success,
   which is #18bf18 -- a flat, slightly acid green that belongs to Bootstrap
   and to nothing here. The lockup SVG uses exactly three colours, #2dc26b,
   #3b82f6 and #2563eb, and the first of those is the green this product
   means. Sampled from themes/default/images/brand/lhq-lockup.svg rather
   than remembered, because two greens four points apart is how this file
   got into trouble the first time. */
#public-login-wrapper .btn-success,
#public-signup-wrapper .btn-success,
#public-signup-login-wrapper .btn-success {
    background-color: #2dc26b!important;
    border-color: #2dc26b!important;
    color: #fff!important;
}
#public-login-wrapper .btn-success:hover,
#public-login-wrapper .btn-success:focus,
#public-signup-wrapper .btn-success:hover,
#public-signup-wrapper .btn-success:focus,
#public-signup-login-wrapper .btn-success:hover,
#public-signup-login-wrapper .btn-success:focus {
    background-color: #3ad47a!important;
    border-color: #3ad47a!important;
    color: #fff!important;
}

/* The submit. Full width, because it is the only thing on the panel you
   are meant to press, and it was a 6px-padded Bootstrap default sitting
   in the middle looking like a cancel. */
#public-login-wrapper .btn-public-form,
#public-signup-wrapper .btn-public-form,
#public-signup-login-wrapper .btn-public-form,
#public-login-wrapper .actions .btn,
#public-signup-login-wrapper .actions .btn {
    display: block;
    width: 100%;
    padding: 12px 18px!important;
    border-radius: 10px!important;
    font-size: 15px;
    font-weight: 700;
}

/* THE GREY SLAB UNDER FORGOT PASSWORD was a spinner that never spins.
   .loader-login is 62px of reserved height for a loading indicator that
   public.js does not use -- it swaps the submit button's own icon for
   fa-spinner instead and never touches this div. Styled only in login.css
   under body.login-page, so on this panel it is unstyled, empty and tall.

   Hidden rather than deleted: the markup is in a shared template and other
   forms may still reach for it. */
#public-login-wrapper .loader,
#public-signup-wrapper .loader,
#public-signup-login-wrapper .loader {
    display: none!important;
}

/* And the message row under it held another 32px, from two causes. The
   wrapper had a line box -- whitespace at the panel's font-size -- which
   zeroing the font-size collapses; the span sets its own back when it
   appears. The rest was `min-height: 22px` on the global `.form-msg`
   (dashboard.css), which reserves a line on every form in the app so that
   an error appearing does not shift the fields under it.

   That reservation is right for a form on a page and wrong for this panel.
   The panel is `position: fixed` and centred by transform, so nothing below
   it can be pushed anywhere -- the only cost of reserving is that everyone
   who signs in without error pays 22px of empty panel for a message they
   never see. Collapsed here, scoped to the three wrappers, so the global
   keeps doing its job everywhere else.

   The colour goes with it: the global sets #cc0000, picked against a white
   form and nearly unreadable on #242424.

   Do not give the span a `display` here. It is hidden by
   `#js-msg-login-modal { display: none }` further up and revealed by
   public.js with .show(), which writes an inline display when it fires. A
   `display: block` in the rule below outranks that ID rule -- one ID plus a
   class beats one ID alone -- and the effect is that the panel opens with
   "Both username and password are required!" already showing in red, before
   the visitor has typed anything. That shipped for a few minutes on
   22 September. Size and spacing here, nothing that governs visibility. */
#public-login-wrapper .app-front-form-msg,
#public-signup-wrapper .app-front-form-msg,
#public-signup-login-wrapper .app-front-form-msg,
#public-login-wrapper .form-msg,
#public-signup-login-wrapper .form-msg {
    font-size: 0;
    margin: 0;
    min-height: 0;
    color: #ed5565;
}
#public-login-wrapper .app-front-form-msg span,
#public-signup-wrapper .app-front-form-msg span,
#public-signup-login-wrapper .app-front-form-msg span,
#public-login-wrapper .form-msg span,
#public-signup-login-wrapper .form-msg span {
    font-size: 13px;
    margin-top: 10px;
}

/* The forgot link sat tight under the button with nothing after it. */
#public-login-wrapper .forgot-link,
#public-signup-login-wrapper .forgot-link {
    margin-top: 2px;
    font-size: 13px;
}

/* The T&C line is small print and was competing with the fields. */
#public-signup-wrapper .form-group p,
#public-signup-login-wrapper .form-group p {
    font-size: 12px;
    color: #6f7885;
    margin: 6px 0 12px;
}

.signup-form-modal .btn-public-form {
  border-color: var(--theme-colour-main)!important;
}
.signup-form-modal .btn-public-form:hover {
  border-color: var(--theme-colour-link-hover)!important;
}
.signup-form-modal .btn-public-form.creator {
  background-color: #2dc26b!important;
  border-color: #2dc26b!important;
}
.signup-form-modal .btn-public-form.creator:hover {
  background-color: var(--theme-colour-main)!important;
  border-color: var(--theme-colour-main)!important;
}

.why-we-care-overlay {
    display: none;
    opacity: 0;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.75);
    z-index: 9997;
}
.why-we-care-modal {
    display: none;
    opacity: 0;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    text-align: center;
    height: 100%;
    max-height: 100%;
    overflow-x: auto;
    z-index: 9998;
}
.why-we-care-overlay-close {
    display: none;
    opacity: 0;
    position: fixed;
    top: 10px;
    right: 15px;
    padding: 0 13px;
    font-size: 32px;
    font-weight: bold;
    color: red;
    background: #000;
    border-radius: 9px;
    cursor: pointer;
    z-index: 9999;
}

#ai-helper-widget-start-business {
    min-height:640px;
    height:auto !important;
}

/* Google Sign In Button */
/* SIGN IN WITH LINKEDIN, DISCORD, TWITCH (15 Oct 2026): under Google's button,
   in its shape and colours, so they read as one set. helpers\SocialSignIn. */
.lhq-soc {
   display: flex;
   align-items: center;
   justify-content: center;
   gap: 10px;
   width: 100%;
   height: 40px;
   margin: 8px 0 0;
   padding: 0 12px;
   box-sizing: border-box;
   border: 1px solid #8e918f;
   border-radius: 4px;
   background: #131314;
   color: #e3e3e3;
   font-family: 'Roboto', arial, sans-serif;
   font-size: 14px;
   font-weight: 500;
   letter-spacing: .25px;
   text-decoration: none;
}
.lhq-soc:hover,
.lhq-soc:focus {
   background: #1f2021;
   color: #fff;
   text-decoration: none;
}
.lhq-soc:focus-visible {
   outline: 2px solid #2563eb;
   outline-offset: 2px;
}
.lhq-soc .lhq-soc-i {
   display: inline-flex;
   width: 20px;
   height: 20px;
}
.lhq-soc .lhq-soc-i svg {
   width: 20px;
   height: 20px;
}
.gsi-material-button {
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
  -webkit-appearance: none;
  background-color: #131314;
  background-image: none;
  border: 1px solid #747775;
  -webkit-border-radius: 4px;
  border-radius: 4px;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  color: #e3e3e3;
  cursor: pointer;
  font-family: 'Roboto', arial, sans-serif;
  font-size: 14px;
  height: 40px;
  letter-spacing: 0.25px;
  outline: none;
  overflow: hidden;
  padding: 0 12px;
  position: relative;
  text-align: center;
  -webkit-transition: background-color .218s, border-color .218s, box-shadow .218s;
  transition: background-color .218s, border-color .218s, box-shadow .218s;
  vertical-align: middle;
  white-space: nowrap;
  width: auto;
  max-width: 400px;
  min-width: min-content;
  border-color: #8e918f;
  width: 100%;
  margin: 15px 0;
}
.gsi-material-button .gsi-material-button-icon {
  height: 20px;
  margin-right: 10px;
  min-width: 20px;
  width: 20px;
}
.gsi-material-button .gsi-material-button-content-wrapper {
  -webkit-align-items: center;
  align-items: center;
  display: flex;
  -webkit-flex-direction: row;
  flex-direction: row;
  -webkit-flex-wrap: nowrap;
  flex-wrap: nowrap;
  height: 100%;
  justify-content: center;
  position: relative;
  width: 100%;
}
.gsi-material-button .gsi-material-button-contents {
  -webkit-flex-grow: 0;
  flex-grow: 0;
  font-family: 'Roboto', arial, sans-serif;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: top;
}
.gsi-material-button .gsi-material-button-state {
  -webkit-transition: opacity .218s;
  transition: opacity .218s;
  bottom: 0;
  left: 0;
  opacity: 0;
  position: absolute;
  right: 0;
  top: 0;
}
.gsi-material-button:disabled {
  cursor: default;
  background-color: #13131461;
  border-color: #8e918f1f;
}
.gsi-material-button:disabled .gsi-material-button-state {
  background-color: #e3e3e31f;
}
.gsi-material-button:disabled .gsi-material-button-contents {
  opacity: 38%;
}
.gsi-material-button:disabled .gsi-material-button-icon {
  opacity: 38%;
}
.gsi-material-button:not(:disabled):active .gsi-material-button-state, 
.gsi-material-button:not(:disabled):focus .gsi-material-button-state {
  background-color: white;
  opacity: 12%;
}
.gsi-material-button:not(:disabled):hover {
  -webkit-box-shadow: 0 1px 2px 0 rgba(60, 64, 67, .30), 0 1px 3px 1px rgba(60, 64, 67, .15);
  box-shadow: 0 1px 2px 0 rgba(60, 64, 67, .30), 0 1px 3px 1px rgba(60, 64, 67, .15);
}
.gsi-material-button:not(:disabled):hover .gsi-material-button-state {
  background-color: white;
  opacity: 8%;
}
.google_login_or {
  margin-bottom: 15px;
  display: block;
  font-size: 20px;
  text-transform: uppercase;
  text-align: center;
}
.google-login-creator {
    display: none;
}

@media screen and (max-width: 500px) {
    #ai-helper-widget-start-business {
        min-height:430px;
    }
}

/* ---------------------------------------------------------------------------
   THE STOREFRONT MENU
   ---------------------------------------------------------------------------
   This panel is the storefront's only navigation, and until now it had no rules
   that placed it. That was a regression with a traceable cause: the flyout used
   to be styled in dashboard.css, which reached a public page whenever the Pages
   module drew one -- the front page included. When the app's own copy of the
   flyout was removed from top_bar.tpl, its eighteen rules went with it, and the
   one that mattered went too:

       .student-menu-flyout { position: fixed; left: -400px; }

   That `left` was the only thing hiding it. public.css had kept the cosmetics
   (a hover colour, a margin) but nothing structural, so with the offset gone the
   panel rendered as what it actually is in the markup -- a static block of links
   sitting between the bar and the hero, pushing the page down by ~280px. On a
   phone it showed list bullets and default-blue links.

   It is rebuilt here rather than restored, because the old version was a black
   slab on a teal bar, and because two of its habits are worth not repeating.

   ONE PANEL AT EVERY WIDTH, not an inline bar on desktop. {$menu} is filtered by
   user_group in PHP, so this same list is four items to a visitor (Home, Sign Up,
   Log In, Contact Us) and seven to a signed-in learner (My Offers, My
   Subscriptions, My Product Purchases, FAQ's, Profile, Logout, Become a Creator).
   Seven inline items do not fit beside a centred logo and the two right-hand
   buttons, and a nav that fits when logged out and overflows when logged in is
   worse than one that never tries. A panel is the same shape either way.

   TRANSFORM, NOT `left`. The old rule animated `left` from -400px, which lays out
   and paints every frame. This translates instead, and the panel's resting
   position is off-canvas by its own width rather than by a guessed 400.

   VIEWPORT-ANCHORED. nav.navbar is `position: fixed` above 429px and
   `position: relative` below it (see the max-width: 429px block above). A panel
   measured from the bar would therefore need two different tops. It is measured
   from the viewport instead and carries its own header, so the bar's own
   positioning stops mattering. */

.student-menu-flyout {
    position: fixed;
    /* UNDER THE BAR, NOT OVER IT.

       This was top:0 with a note explaining that the panel carried its own
       header precisely so it could cover the bar, rather than depend on the
       height of "a bar whose height and positioning both change with width".
       The constraint was real; the conclusion was the expensive one. Covering
       the bar hides the hamburger, and the hamburger changing state is the
       only thing on screen that says the menu is open -- which is exactly the
       feedback a logged-in person already gets from the app's rail, opening
       at top:60px underneath its own bar.

       So the height is measured instead of assumed. measurePublicBar() in
       dashboard.js sets --public-bar-h from the bar's own bounding box, on
       load and on resize. The fallback is this install's current 65px, so a
       stylesheet arriving before the script is wrong by a pixel or two rather
       than by the whole bar. */
    top: var(--public-bar-h, 65px);
    left: 0;
    bottom: 0;
    /* Above nav.navbar, which is z-index 99999 -- still, because the panel
       must clear everything else on the page. It simply starts lower. */
    z-index: 100001;
    width: 300px;
    max-width: 86vw;
    margin: 0;
    padding: 0;
    background: #002230;
    border-right: 1px solid rgba(255,255,255,.08);
    box-shadow: 2px 0 26px rgba(0,0,0,.45);
    transform: translateX(-102%);
    transition: transform .28s cubic-bezier(.4,0,.2,1);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.student-menu-flyout.flyout-open {
    transform: translateX(0);
}
/* body.courses had its own -15px nudge when this was in the flow. It is not in
   the flow any more, and a margin on a fixed panel would just push it off line. */
body.courses .student-menu-flyout,
.student-menu-flyout {
    margin-top: 0;
}

/* The panel's own header. It exists so the panel can be anchored to the viewport
   rather than to a bar whose height and positioning both change with width. */
/* THE PANEL'S OWN HEADER IS GONE, and it goes with the reason it existed.
   It carried a "Menu" title and a close button because the panel covered the
   bar and there was nothing else to close it with. The panel now opens
   beneath the bar, so the hamburger is visible, lit, and toggles -- a second
   bar saying "Menu" directly under the real one is a row of chrome repeating
   what is immediately above it.

   Closing still has three ways out: the hamburger, the backdrop, and Escape,
   all bound in dashboard.js and none of them dependent on this element. */
.student-menu-head {
    display: none;
}
.student-menu-head-unused {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 61px;
    padding: 0 10px 0 22px;
    background: #003142;
    border-bottom: 1px solid rgba(255,255,255,.09);
}
.student-menu-title {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: rgba(255,255,255,.5);
}
.student-menu-close {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    margin: 0;
    border-radius: 8px;
    color: rgba(255,255,255,.65);
    font-size: 17px;
    cursor: pointer;
    transition: background .15s, color .15s;
}
.student-menu-close:hover,
.student-menu-close:focus {
    background: rgba(255,255,255,.08);
    color: #fff;
    text-decoration: none;
}

/* The backdrop is a sibling that follows the panel, so it can be opened by the
   same class the existing handler already toggles -- no second class to keep in
   step. It sits under the panel on z-index, not on DOM order. */
.student-menu-backdrop {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 100000;
    background: rgba(0,14,20,.55);
    opacity: 0;
    pointer-events: none;
    transition: opacity .28s ease;
}
.student-menu-flyout.flyout-open ~ .student-menu-backdrop {
    opacity: 1;
    pointer-events: auto;
}

/* The list. `padding-left: 0` and the list-style reset are not tidying: without
   them a phone showed real bullets, because nothing above ever restyled this ul. */
.student-menu-flyout .student-menu-list {
    flex: 1 1 auto;
    margin: 0;
    padding: 10px 0 24px;
    list-style: none;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}
.student-menu-flyout li.standard-menu-item,
.student-menu-flyout .student-menu-list > li {
    display: block;
    margin: 0;
    padding: 0;
    background: none;
    border: 0;
    border-left: 3px solid transparent;
    transition: background .15s, border-color .15s;
}

/* Two of these links carry .btn-public-signup and .btn-public-login -- the same
   classes as the pill buttons in the bar -- so they were inheriting
   `background:#000!important; border:2px solid #fff!important; border-radius:15px`
   from the button rules further up. On an inline element a pill border draws only
   its two end arcs, which is where the stray "(" and ")" on either side of Sign Up
   came from. They are links here, not buttons, so the button skin is taken off.
   `!important` is required to reach the source declarations, not preferred. */
.student-menu-flyout .student-menu-list a,
.student-menu-flyout .student-menu-list a.btn-public-signup,
.student-menu-flyout .student-menu-list a.btn-public-login {
    display: flex;
    align-items: center;
    min-height: 48px;
    padding: 12px 22px !important;
    background: none !important;
    border: 0 !important;
    border-radius: 0 !important;
    color: rgba(255,255,255,.86) !important;
    font-size: 15px !important;
    line-height: 1.3;
    text-decoration: none;
    transition: color .15s;
}
.student-menu-flyout .student-menu-list a i {
    width: 20px;
    margin-right: 12px;
    font-size: 15px !important;
    text-align: center;
    color: rgba(255,255,255,.45);
    transition: color .15s;
}
.student-menu-flyout .student-menu-list .nav-label {
    display: block !important;
}

/* Hover and focus. The rule this replaces painted the whole row #2f77db -- a blue
   that appears nowhere else on the storefront, whose bar and footer are #003142
   and whose calls to action are #2dc26b. The accent is the green. */
.student-menu-flyout li.standard-menu-item:hover,
.student-menu-flyout li.standard-menu-item:focus-within,
.student-menu-flyout .student-menu-list > li:hover {
    background: rgba(45,194,107,.12);
    border-left-color: #2dc26b;
}
.student-menu-flyout li.standard-menu-item:hover > a,
.student-menu-flyout li.standard-menu-item:focus-within > a,
.student-menu-flyout .student-menu-list > li:hover > a {
    color: #fff !important;
}
.student-menu-flyout li.standard-menu-item:hover > a i,
.student-menu-flyout .student-menu-list > li:hover > a i {
    color: #2dc26b;
}

/* "Become a Creator" -- the one row that is a call to action rather than a
   destination, and the reason a learner opens this menu at all. It was a flat
   green block before; it reads as a button now without leaving the list. */
.student-menu-flyout li.upgrade {
    margin: 14px 16px 4px;
    border-left: 0;
    border-radius: 10px;
    background: #2dc26b;
}
.student-menu-flyout li.upgrade > a {
    justify-content: center;
    min-height: 44px;
    padding: 11px 16px !important;
    color: #fff !important;
    font-weight: 700;
}
.student-menu-flyout li.upgrade > a i {
    color: rgba(255,255,255,.85);
}
.student-menu-flyout li.upgrade:hover {
    background: #3ad47a;
    border-left: 0;
}
.student-menu-flyout li.upgrade:hover > a,
.student-menu-flyout li.upgrade:hover > a i {
    color: #fff !important;
}

/* Second-level rows. These were `display: none` with nothing on the storefront to
   open them, so any child item was unreachable. metisMenu is initialised on this
   list now (see dashboard.js); these are its open and closed states. */
.student-menu-flyout .nav-second-level {
    margin: 0;
    padding: 0;
    list-style: none;
    background: rgba(0,0,0,.22);
}
.student-menu-flyout .nav-second-level li a {
    min-height: 42px;
    padding: 10px 22px 10px 54px !important;
    font-size: 14px;
    color: rgba(255,255,255,.7) !important;
}
.student-menu-flyout .nav-second-level li a:hover {
    color: #fff !important;
    background: rgba(255,255,255,.05) !important;
}
.student-menu-flyout .student-menu-list a .arrow {
    margin-left: auto;
    font-size: 12px;
    color: rgba(255,255,255,.35);
}

/* The button that opens it. Square, 40px, matching the close inside the panel --
   and 40px because below 579px this was 3px 6px of padding around a 14px glyph,
   which is a tap target of about 26px against a 44px guideline. */
.top-student-menu {
    display: inline-block !important;
    margin: 0 0 0 15px;
    padding: 0 !important;
    vertical-align: middle;
}
/* THE PUBLIC SIDE HAD ITS OWN GREEN, and this file was where it lived:
   #00bf63 on the menu button, the Sign Up chip and the flyout's hover, against
   #2dc26b everywhere in the app. Four points apart -- far enough to read as a
   mistake when the two met, close enough that nobody caught it while they never
   did. brandGuide.html lists it under open conflicts and rules on it: "The app
   is already on the right one; the storefront is the outlier."

   They met on 22 September, when the marketplace got a menu item and a
   logged-in creator saw the public bar for the first time. Martin: "Why does
   the top bar look different and have green colors in the hamburger menu."

   Eight values changed here and nowhere else in the repo -- six hex, one
   rgba() of the same colour that a hex search misses, and the #00d16d hover,
   now --green-lit #3ad47a. Four uses of #2dc26b were already in this file,
   which is what made the split visible inside one stylesheet. */
/* THE SAME TOGGLE THE APP HAS, and deliberately the same rule: OUTLINE
   WHILE THE MENU IS AWAY, FILLED WHILE IT IS HERE. chrome.css says it in
   those words for the creator and learner rails; this is the public bar
   catching up, so a person who signs up does not meet a third behaviour for
   the same control.

   BLUE, NOT GREEN. Green on this platform means go and price -- a menu
   button is neither, and #2dc26b sitting beside the green Sign Up button
   made two different promises in one bar. #2563eb is the app's toggle
   colour and is one of the three in the logo.

   body.menu-open is set by openStudentMenu() in dashboard.js, which already
   existed, so this needs no script change. */
.top-student-menu .student-nav {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    margin: 0;
    padding: 0 !important;
    min-height: 0;
    background-color: transparent;
    border: 1px solid rgba(91,147,255,.55);
    border-radius: 9px;
    color: #5b93ff;
    font-size: 16px;
    cursor: pointer;
    transition: background-color .15s, border-color .15s, color .15s, transform .15s;
}
.top-student-menu .student-nav:hover,
.top-student-menu .student-nav:focus {
    background-color: rgba(37,99,235,.20);
    border-color: rgba(91,147,255,.85);
    color: #fff;
}
/* Menu here: filled. */
body.menu-open .top-student-menu .student-nav {
    background-color: #2563eb;
    border-color: #2563eb;
    color: #fff;
}
body.menu-open .top-student-menu .student-nav:hover,
body.menu-open .top-student-menu .student-nav:focus {
    background-color: #1d4fd7;
    border-color: #1d4fd7;
    color: #fff;
}
/* No lift on a touch screen: there is no hover there, so the transform would
   stick to whatever was tapped last. */
@media (hover: hover) {
    .top-student-menu .student-nav:hover {
        transform: translateY(-1px);
    }
}

/* The page behind the panel should not scroll while it is open. */
body.menu-open {
    overflow: hidden;
}

/* The bar's right-hand cluster. Below 500px these collapse to bare icons, but
   with no gap between them and no tap target around them. */
@media (max-width: 500px) {
    .top-button-menu {
        display: flex;
        align-items: center;
        gap: 0;
        margin-top: 0 !important;
        margin-right: 4px;
    }
    .top-button-menu > a {
        display: inline-flex !important;
        align-items: center;
        justify-content: center;
        width: 40px;
        height: 40px;
        margin: 0 !important;
        padding: 0 !important;
        border-radius: 9px !important;
    }
    .top-button-menu > a i {
        margin: 0;
        font-size: 17px;
    }
}

/* nav.navbar is `display: flex` with `align-items: normal`, so a flex item that
   does not set its own alignment stretches the full 65px and puts its contents at
   the top. That is why the menu button sat against the bar's top edge while the
   right-hand icons -- which are inside their own centred flex box -- sat correctly
   on the line. This centres the button in its own item box instead of changing the
   bar's alignment, which the desktop search form is positioned against. */
.top-student-menu {
    display: inline-flex !important;
    align-items: center;
}
/* HIDDEN FOR A SIGNED-OUT VISITOR, and it has to be a class rather than
   the inline `style` the cluster next to it uses, because three separate
   rules in this file set this element's display with !important and an
   inline style without !important loses to every one of them. The first
   attempt was inline and the hamburger simply stayed on screen.

   Output.class.php decides which viewer gets the class; the reasoning for
   hiding it at all -- and for keeping it when signed in -- is there. */
.top-student-menu.bar-menu-hidden {
    display: none !important;
}

/* The logo is centred on the bar by logo.css: `position: absolute; left: 50%;
   top: 0; bottom: 0; transform: translateX(-50%); margin: 0`. The margins below
   were written when it still sat in the flow, and they are !important, so they
   outlive that: on a phone they were a 6px drop and a 15px shove left of a logo
   that is otherwise dead centre. Zeroed at the same weight, and later in the file
   so they win on order rather than on a specificity bump. */
@media (max-width: 500px) {
    nav.navbar .img-logo-a {
        margin: 0 !important;
    }
}

/* The right-hand icons. Below 500px the buttons drop their labels and the rules
   above strip their skin -- but .btn-public-signup is restyled again further down
   the file with `background:#000!important; border:2px solid #fff!important`, which
   is later and therefore wins, so Sign Up kept a black chip with a white outline
   while Log In next to it was a bare glyph. Two buttons of equal weight, drawn
   differently for no reason anyone chose.

   Given a choice about which one to emphasise: Sign Up is the storefront's whole
   purpose, so it is the filled one, in the same green as the menu button on the
   other side of the bar. Log In is quiet next to it. (Search was the third icon
   here and shared Log In's quiet treatment; it is gone -- see top_bar.tpl.) */
@media (max-width: 500px) {
    /* THE TWO COLOURS SURVIVE THE BREAKPOINT. This block used to fill
       Sign Up green and leave Log In a white glyph, which is the
       opposite emphasis to the desktop bar above, where Log In is the
       filled green one. The same two controls disagreed about which of
       them mattered depending on how wide the window was.

       They now carry the same hues they carry everywhere else: Log In
       green, Sign Up blue. At this size both are 40px glyphs, so the
       filled one is Sign Up -- a filled chip is easier to hit and to
       find than an outline, and the outline treatment does not survive
       being shrunk to an icon anyway. */
    .top-button-menu > a.btn-public-login {
        background: none !important;
        border: 0 !important;
        color: #2dc26b !important;
    }
    /* No sweep at this size. The button is a 40px glyph with no outline
       for it to run inside, and there is no hover on a phone to start
       it -- it would only ever fire as a flash on tap. */
    .top-button-menu > a.btn-public-login::before,
    .top-button-menu > a.btn-public-login::after {
        display: none;
    }
    .top-button-menu > a.btn-public-signup {
        background: #2563eb !important;
        border: 0 !important;
        color: #fff !important;
    }
    .top-button-menu > a.btn-public-login i {
        color: #2dc26b !important;
    }
    .top-button-menu > a.btn-public-signup i {
        color: #fff !important;
    }
    .top-button-menu > a:hover {
        opacity: .85;
    }
}

/* THE 419px BLOCK THAT STOOD HERE IS GONE, and its arithmetic is now the whole
   bar's rather than one breakpoint's.

   It dropped the search magnifier below 419 because the centred logo and three
   icons could not both have the room: the menu button takes 55px on the left,
   three 40px icons and a 4px margin take 124 on the right, and a centred 150px
   wordmark therefore needs 2 x 124 + 150 = 398px of bar before something touches.
   At 320 the magnifier landed on top of "HQ".

   Search is now gone at every width, so the two icons that remain need
   2 x 84 + 150 = 318px -- clear at 320 and 80px in hand at 400, with no rule
   needed to make it so. Should search ever come back, this is the sum to redo. */

/* Logout is not a destination like the rows above it, and it was sitting directly
   against Become a Creator -- an account action butted up against the one call to
   action in the list. A hairline separates the two kinds of row. The class comes
   from the module name, the same way Courses2 and Users7 do on their own rows. */
.student-menu-flyout li.standard-menu-item.Logout {
    margin-top: 8px;
    border-top: 1px solid rgba(255,255,255,.09);
}

/* Logout hovers red here too. The storefront's menu is a different object from
   the app's rail -- this one is CSS where the rail's is the spotlight in
   chrome.js -- but it holds the same row and it should say the same thing about
   it. #ed5565 is main.css's danger colour; the green above is for the rows you
   cannot regret. */
.student-menu-flyout li.standard-menu-item.Logout:hover,
.student-menu-flyout li.standard-menu-item.Logout:focus-within {
    background: rgba(237,85,101,.12);
    border-left-color: #ed5565;
}
.student-menu-flyout li.standard-menu-item.Logout:hover > a,
.student-menu-flyout li.standard-menu-item.Logout:focus-within > a,
.student-menu-flyout li.standard-menu-item.Logout:hover > a i {
    color: #ed5565 !important;
}

/* ===================================================================
   THE CONTACT FORM'S FIELDS
   -------------------------------------------------------------------
   Five white boxes stacked down a #1d1d1d page, with dark grey text in
   them -- Bootstrap's .form-control defaults, never restyled, on a page
   that went dark around them. The same thing the auth modal had this
   morning and the same answer: the panel colour, a hairline border and
   the text colour the rest of the product uses.

   SCOPED TO .contact-form, NOT TO .app-input. That class is on public
   forms all over the site, including inside landing pages -- which a
   creator designs, and which may well be light. Dark fields injected
   into somebody's pale landing page would be a worse bug than the one
   being fixed. Anywhere else with this problem wants the same treatment
   and its own look first.

   THE !important IS FOR A STALE INLINE COLOUR. The first field carries
   `style="border-color: rgb(204, 0, 0)"` in the markup the server
   sends -- page content, saved that way in the builder, not something
   the code does -- and an inline style cannot be answered any other
   way. The validator no longer writes inline colours (see
   forms_public.js), so nothing else is being fought here.
   =================================================================== */
.contact-form .form-control,
.contact-form .app-input {
    background-color: #1c1c1c !important;
    border: 1px solid rgba(255,255,255,.12) !important;
    border-radius: 10px !important;
    color: #e9edf2 !important;
    height: auto;
    padding: 11px 13px;
    box-shadow: none;
    transition: border-color .16s ease, box-shadow .16s ease;
}
.contact-form .form-control::placeholder,
.contact-form .app-input::placeholder {
    color: #6f7885;
    opacity: 1;
}
.contact-form .form-control:focus,
.contact-form .app-input:focus {
    border-color: #2dc26b !important;
    outline: none;
    box-shadow: 0 0 0 3px rgba(45,194,107,.18);
}
/* The flag the validator raises now. --danger, not the #cc0000 it used
   to write inline, which is unreadable on a dark field. */
.contact-form .form-control.field-invalid,
.contact-form .app-input.field-invalid {
    border-color: #ed5565 !important;
    box-shadow: 0 0 0 3px rgba(237,85,101,.16);
}

/* THE "18 OR OVER" BOX (27 Sep 2026, Neil) -- on every signup form, where the
   line "By signing up you accept our T&C's" used to be. A row: the box, then
   the sentence, with the whole label clickable. Inherits the form's colour,
   so it reads on the light modal and on a creator's dark page alike. */
.app-front-form .signup-adult-label {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 4px 0 12px;
    font-size: 13px;
    font-weight: 400;
    line-height: 1.4;
    text-align: left;
    cursor: pointer;
}
.app-front-form .signup-adult-label input {
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    margin: 1px 0 0;
    accent-color: #2dc26b;
    cursor: pointer;
}
.app-front-form .signup-adult-label a {
    text-decoration: underline;
}

/* ---- TWO-STEP SIGN-IN: the code view of the sign-in box (2 Oct 2026) ------
   Output::authViews draws it while a sign-in waits for its code. One box
   for the six digits (or an app user's backup code), spaced like a code. */
#public-login-wrapper .ts-ico {
    width: 44px;
    height: 44px;
    margin: 0 auto 12px;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(45,194,107,.12);
    color: #3ad47a;
}
#public-login-wrapper .ts-ico svg { width: 22px; height: 22px; }
#public-login-wrapper .ts-view p b { color: #fff; }
#public-login-wrapper .form-control.ts-code {
    height: 54px;
    text-align: center;
    font-size: 24px;
    font-weight: 700;
    letter-spacing: .35em;
}
#public-login-wrapper .form-control.ts-code::placeholder {
    font-size: 14px;
    font-weight: 400;
    letter-spacing: 0;
}
#public-login-wrapper .ts-trust {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    margin: 4px 0 16px;
    padding: 10px 12px;
    border-radius: 10px;
    background: #1c1c1c;
    border: 1px solid rgba(255,255,255,.08);
    text-align: left;
    font-size: 13px;
    font-weight: 400;
    color: #c9d0d8;
    cursor: pointer;
}
#public-login-wrapper .ts-trust input { margin: 2px 0 0; width: 16px; height: 16px; flex: none; accent-color: #2563eb; }
#public-login-wrapper .ts-trust small { display: block; color: #6f7885; font-size: 12px; }
#public-login-wrapper .ts-view .btn-success { width: 100%; }
#public-login-wrapper .ts-links { display: flex; justify-content: center; gap: 16px; margin-top: 4px; }
#public-login-wrapper .ts-links form { margin: 0; }
#public-login-wrapper .ts-link {
    border: 0;
    background: none;
    padding: 0;
    font: inherit;
    font-size: 13px;
    color: color-mix(in srgb, #2563eb 55%, white);
    text-decoration: none;
    cursor: pointer;
}
#public-login-wrapper .ts-link:hover { text-decoration: underline; }
#public-login-wrapper .ts-note { margin: 14px 0 0; font-size: 12px; color: #6f7885; }

/* NO GAP ABOVE A CREATOR'S STORE (3 Oct 2026, Martin: "there's space before
   the page actually starts"). dashboard.css gives every body 61px at the top,
   !important, for the old fixed bar; a store has no bar of ours above it
   (top_bar_store.tpl), so the 61px was a dark band over the creator's page.
   body.lhq-bare is set by Output for exactly those pages; body.v2 does the
   same for the app (v2.css). */
body.lhq-bare { margin-top: 0 !important; }

/* reCAPTCHA'S BADGE, HIDDEN (3 Oct 2026, Martin). Google allows it when the
   form says so instead, which the sign-in and sign-up boxes now do (.rc-note,
   footer_public.tpl). The script itself only loads when one of those forms is
   started -- lhqCaptcha in public.js. */
.grecaptcha-badge { visibility: hidden !important; }
.rc-note { margin: 14px 0 0; font-size: 11.5px; line-height: 1.45; color: #6f7885; text-align: center; }
.rc-note a { color: #98a1ad; text-decoration: underline; }
/**
 *    © Copyright 2016 Variation Design Consultants Limited | copyright@variationdesign.co.uk
 *    All rights reserved.
 *
 *    The account's brand colours, published as CSS custom properties.
 *
 *    WHY THIS FILE EXISTS. The platform has always had per-account colours -- an
 *    account sets them in Settings and they land in the session as main_colour,
 *    link_colour and the rest. But the only way to USE one has been the [$TOKEN]
 *    substitution that styles/css/dynamic.php and public_dynamic.php run over the
 *    stylesheets they concatenate. A stylesheet that is not in one of those bundles
 *    never sees a brand colour at all.
 *
 *    Most module stylesheets are not in them. AjaxStylesJS::returnStyles() emits a
 *    plain <link rel="stylesheet" href="..."> straight to the file, so the browser
 *    fetches it from disk with no PHP anywhere near it -- which is why
 *    modules/Courses/styles/courses.css contains hardcoded #2563eb and #3078db and
 *    could not do otherwise.
 *
 *    So the tokens are resolved ONCE here, into custom properties, and after that
 *    any stylesheet in the platform can use var(--lhq-brand) with no parsing at all.
 *    Custom properties are inherited and resolved at use time, so it does not matter
 *    that this file loads before or after the one using them.
 *
 *    ALWAYS PASS A FALLBACK. var(--lhq-brand, #2563eb), never a bare var().
 *
 *    This is not defensive habit, it is a real case: Styles::saveStylesFiles() seeds
 *    every one of these to an empty string and only fills them if the account has a
 *    settings record. An account without one emits `--lhq-brand: ;`, which is a
 *    valid but EMPTY custom property -- and a bare var() referring to it makes the
 *    whole declaration invalid at computed-value time, which is to say the colour
 *    does not fall back to anything, it disappears. A fallback in the var() is what
 *    turns that into the platform default instead of a missing rule.
 *
 *    HOW IT IS LOADED. Appended by both styles/css/dynamic.php and
 *    styles/css/public_dynamic.php, the same way logo.css is, so the variables exist
 *    on logged-in screens and on the public storefront alike.
 */

:root {
    /* The account's primary colour. Most of the platform's own chrome uses a fixed
       cobalt rather than this; the two are different things and should stay so --
       this is the CREATOR's colour, for surfaces that represent them. */
    --lhq-brand: #00437a;
    --lhq-brand-light: #f8fbfd;

    --lhq-link: #005c9b;
    --lhq-link-hover: #7d0082;

    --lhq-text: #2d2d2b;
    --lhq-bg: #ffffff;

    /* A family NAME, not a stack -- the theme stores one face. Anything using it
       should supply its own fallbacks after it:
       font-family: var(--lhq-font, open_sansregular), Helvetica, Arial, sans-serif; */
    --lhq-font: open_sansregular;
}

/* ===================================================================
   THE FULL-WIDTH PAGE WRAPPER
   -------------------------------------------------------------------
   Pages.class.php gives the course and marketplace pages a wrapper
   that runs the full width instead of Bootstrap's fixed .container.
   Its padding used to be an inline style on that div, which meant no
   media query could answer it -- on a 375px phone it held 20px a side
   that no breakpoint could reach.

   IT LIVES IN brand.css BECAUSE BOTH BUNDLES LOAD IT. The first
   version of this rule went into public.css, and public.css is only in
   the public bundle -- so a signed-in viewer, who gets the app bundle
   and the app chrome, lost the 20px entirely and the marketplace ran
   edge to edge. brand.css and logo.css are the only two sheets in both
   styles/css/dynamic.php and styles/css/public_dynamic.php.

   The row reset below is not tidying either. Signed OUT the Bootstrap
   row sits flush and its column's padding is the gutter; signed IN the
   row carries its -15 margins, so the same column padding nets to
   nothing and the cards touched the glass. Zeroing the margins makes
   the two states agree on one 16px gutter instead of 16 and 0.
   =================================================================== */
.container-content-full {
    padding: 0 20px;
}
@media (max-width: 600px) {
    .container-content-full {
        padding-left: 8px;
        padding-right: 8px;
    }
    .container-content-full > .row {
        margin-left: 0;
        margin-right: 0;
    }
    .container-content-full > .row > [class*="col-"] {
        padding-left: 8px;
        padding-right: 8px;
    }
}

/* ===================================================================
   THE COOKIE BAR
   -------------------------------------------------------------------
   It was three declarations of inline <style>, duplicated in
   header.tpl and header_public.tpl, and the two copies had already
   drifted -- the public one styles a Reject button the app one has
   never had. Both are gone; this is the one copy, in the one sheet
   both bundles load.

   NOTHING IN IT WAS A BRAND COLOUR. Accept was #090, a dark green in
   no palette this company has and nowhere near --green #2dc26b.
   Reject was #cc0000, which is --danger's job, and DECLINING COOKIES
   IS NOT AN ERROR -- it is one of the two answers to a fair question.
   Painting it the colour that means "something has gone wrong"
   everywhere else in the product is the same mistake as the Log In
   hover that turned red.

   So: Accept is the green one because it is what the button does, and
   Reject is a quiet outline. Equal size, equal weight, no dark
   pattern -- the one that keeps your data is not harder to press than
   the one that does not.

   A CARD, NOT A STRIP. Fixed full-width bar, centred text and two
   buttons wrapping onto their own line is what made it read as
   boilerplate. On a wide screen it is a panel in the corner with the
   text left and the buttons right; on a phone it is a sheet across the
   bottom with the buttons side by side under the text, where thumbs
   are.
   =================================================================== */
#cookieConsent {
    display: none;                 /* the plugin turns this on */
    position: fixed;
    z-index: 65000;
    right: 16px;
    bottom: 16px;
    left: auto;
    width: auto;
    max-width: 440px;
    box-sizing: border-box;
    padding: 16px 18px;
    background: #242424;
    border: 1px solid rgba(255,255,255,.09);
    border-radius: 14px;
    box-shadow: 0 18px 44px rgba(0,0,0,.5);
    color: #c8ced6;
    font-size: 13px;
    line-height: 1.5;
    text-align: left;
}
#cookieConsent .cookieText {
    margin: 0;
    color: #c8ced6;
    font-size: 13px;
    line-height: 1.5;
}
/* The buttons get their own row, and share it. Equal width on a phone so
   neither answer is the easier one to hit -- the one that keeps your data
   is not the harder one to press. */
#cookieConsent .cookieActions {
    display: flex;
    gap: 8px;
    margin-top: 12px;
}
#cookieConsent button {
    appearance: none;
    margin: 0;
    padding: 9px 16px;
    border-radius: 10px;
    font-size: 13px;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
    transition: background-color .16s ease, border-color .16s ease, color .16s ease;
}
#cookieConsent button.cookieAccept {
    background: #2dc26b;
    border: 1px solid #2dc26b;
    color: #fff;
}
#cookieConsent button.cookieAccept:hover,
#cookieConsent button.cookieAccept:focus-visible {
    background: #3ad47a;
    border-color: #3ad47a;
}
/* Quiet, not red. See the note above. */
#cookieConsent button.cookieReject {
    background: transparent;
    border: 1px solid rgba(255,255,255,.18);
    color: #98a1ad;
}
#cookieConsent button.cookieReject:hover,
#cookieConsent button.cookieReject:focus-visible {
    border-color: rgba(255,255,255,.34);
    color: #e9edf2;
}
/* A sheet on a phone. Corner-to-corner at the bottom rather than a
   floating card, because a card with 16px of page showing either side
   of it on a 375px screen is just a strip with rounded ends. */
@media (max-width: 600px) {
    #cookieConsent {
        right: 0;
        left: 0;
        bottom: 0;
        max-width: none;
        padding: 14px 16px calc(14px + env(safe-area-inset-bottom, 0px));
        border-width: 1px 0 0;
        border-radius: 14px 14px 0 0;
    }
    /* Equal halves of the row, by growing rather than by a width
       calculation -- the flex gap already owns the 8px between them and
       a calc that also subtracts it would be the same number written
       twice, in two places, waiting to disagree. */
    #cookieConsent .cookieActions > button {
        flex: 1 1 0;
    }
}
/**
 *    © Copyright 2016 Variation Design Consultants Limited | copyright@variationdesign.co.uk
 *    All rights reserved.
 *
 *    The logo treatment, in its own file so that it loads on EVERY surface.
 *
 *    WHY THIS IS NOT IN dashboard.css ANY MORE. It was, and that is precisely why the
 *    climber never ran on the public site. dashboard.css is registered by four modules
 *    only -- Dashboard, Landing, Pages and PageBuilder -- so whether these rules reached
 *    a given page depended on which module happened to draw it. The public home page got
 *    them (Pages registers dashboard.css into the PUBLIC bundle, which is easy to miss);
 *    a page drawn by any other module did not.
 *
 *    The same reasoning later moved the top bar and the side menu out of dashboard.css
 *    into chrome.css, which is why the line references below name that file rather than
 *    the one these rules were originally lifted from.
 *
 *    That matters more than a missing animation. The brand lockup is INLINED as an <svg>
 *    by Output.class.php, and lhq-lockup.svg carries a viewBox and no width or height --
 *    deliberately, so it scales. An inline SVG sized that way and given no CSS height
 *    fills its container: measured at 1260x218 in a 1306px bar, against the 32px it is
 *    meant to be. So the one rule that MUST always be present is the height below. The
 *    animation is the nice part; the sizing is the load-bearing part.
 *
 *    HOW IT IS LOADED. Appended by styles/css/dynamic.php and styles/css/public_dynamic.php
 *    after every other stylesheet those bundles emit, and before the theme's custom_css so
 *    an account can still override it. Last position is not cosmetic: chrome.css's
 *    own .img-logo-a rule (the one under its "Sidebar" heading)
 *    sets .img-logo-a { width: 160px } and this file sets width: auto at equal
 *    specificity, so whichever comes second wins. It has to be this one.
 */

/* ---------------------------------------------------------------------------
   The logo, on hover and while the app is busy: a ball falling down the steps.

   TWO TREATMENTS, because the logo is whatever the account uploaded.

   A RASTER is one flat rectangle. You can move it; you cannot move anything inside
   it. So jpg, png and gif logos get a band of light travelling across on a 105deg
   angle, up as well as across, plus a small lift. It works on artwork we know
   nothing about and asks nothing of it.

   AN SVG is inlined by Output.class.php rather than sent as a src, because an <img>
   pointing at an SVG is a sealed document: page CSS cannot reach inside it and it
   takes no pointer events, so hovering the anchor can never drive anything within
   the drawing. Inlined, the parts are addressable, and the brand lockup carries a
   ball and three lights.

   THE BALL (3 Oct 2026, Martin, replacing the climber that went UP the stairs):
   it falls onto the top step, bounces down one, two, three, drops through the
   floor to the left of the bottom step, and the next one is already falling in
   at the top; each step lights as the ball lands on it. Its rules are in the
   GENERATED block further down, written with the lockup itself by
   Planning/steps/lhq-logo-build.js from a physics simulation, so the keyframes
   are sampled parabolas rather than hand-placed easings. Change it there.
   --------------------------------------------------------------------------- */
/* THE BAR IS WHAT THE LOGO IS CENTRED IN, so the bar has to say so (29 Sep
   2026, Martin: the logo "appearing oddly on certain pages"). The rule below
   is absolute with top:0 and bottom:0, and relied on Bootstrap's
   `.navbar { position: relative }` to make the bar its box. A public page
   without Bootstrap -- Privacy, Help -- left the bar static, so the anchor
   stretched down the whole page and drew the logo in the middle of it,
   over the content. Said here, next to the rule that needs it. */
nav.navbar:has(> .img-logo-a) {
    position: relative;
}
.img-logo-a {
    /* CENTRED ON THE BAR, at every width.

       Absolute rather than in flow, because the two sides are not the same
       size -- the hamburger is about 63px and the links on the right 124 to
       218 depending on who is looking -- so an in-flow logo sits visibly right
       of centre and moves as the right-hand side changes. Taking it out of the
       flow means the bar centres it and neither neighbour has a vote.

       Nothing is in the middle to collide with: the bar holds the hamburger,
       this, and the links. It used to hold .courses-search-top-bar too, which
       was display:none at every width and only ever shown by the mobile toggle,
       as a drawer beneath the bar rather than inside it -- that is gone now, so
       there is one less thing in the middle than when this was measured at 768,
       800, 900, 1100 and 1400 and the gap was never less than 340px. */
    position: absolute;
    left: 50%;
    /* AND vertically -- by spanning the bar rather than by a percentage.

       left:50% with a translateX centred it across the bar and left it wherever
       the flow had put it down the bar: measured on a phone, the bar centre is
       32.5 and the logo sat at 38. `top: 50%` then made it worse, not better,
       landing at 42.5 -- the percentage was resolving against a containing
       block 85px tall rather than the 65px bar, so half of it was not half the
       bar.

       top:0 bottom:0 does not care what that box measures. The anchor stretches
       the full height of whatever it is in and centres the drawing inside
       itself, which is what align-items below is already for. */
    top: 0;
    bottom: 0;
    height: auto;
    transform: translateX(-50%);
    /* chrome.css gives this anchor `margin: 0 40px 0 10px`, which was fine while
       it sat in the flow and is a 10px shove to the right once it is centred on
       left:50%. Measured: dead centre on a phone where the mobile rule already
       zeroed it, and 10px off on every desktop width. */
    margin: 0;
    isolation: isolate;
    width: auto;
    /* THESE THREE USED TO COME FROM chrome.css -- its two .img-logo-a rules, one under
       the "Sidebar" heading and one in the logo-centring block -- and this file has to
       stand on its own now, because the pages that most needed it were the ones that
       never loaded that file. display and align-items are a no-op wherever the bar is
       already flex -- a flex item's inline-flex is blockified to flex -- and they give
       the anchor a box to centre in everywhere else. overflow is what clips the sweep
       to the logo; without it the band of light runs off the side of the mark. */
    display: inline-flex;
    align-items: center;
    overflow: hidden;
    /* Headroom for the raster lift. The anchor carries overflow:hidden, which is
       what clips the sweep to the logo, so without this it would clip the top off
       anything that rises. Symmetric, so the flex centring set further up is
       unchanged, and 46px still sits inside the 65px bar. */
    padding: 6px 0;
}

/* --- the raster treatment ------------------------------------------------- */
.img-logo-a .img-logo {
    transition: transform 0.32s cubic-bezier(0.22, 0.9, 0.28, 1);
}
.img-logo-a:hover .img-logo {
    transform: translateY(-2px);
}

/* Only when there is no inlined SVG. A sweep of light across the lockup while the
   climber is running is two things competing for the same second. */
.img-logo-a:not(:has(.img-logo-svg))::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: linear-gradient(105deg,
        rgba(255, 255, 255, 0) 42%,
        rgba(255, 255, 255, 0.38) 50%,
        rgba(255, 255, 255, 0) 58%);
    transform: translateX(-130%);
}
.img-logo-a:not(:has(.img-logo-svg)):hover::after {
    animation: lhq-logo-sweep 0.72s cubic-bezier(0.4, 0, 0.2, 1);
}

/* THE ACCOUNT THAT HAS NO CLIMBER TO RUN.
 *
 * The climber lives inside the brand lockup, and the lockup is only inlined when
 * that is the logo. An account that uploaded its own jpg or png has a raster: one
 * flat rectangle, nothing inside it to move. So a busy state that only animated the
 * climber would say nothing at all on most accounts -- and this is the signal that
 * replaced the spinner, so saying nothing is not an option.
 *
 * The sweep is already this file's answer for artwork it knows nothing about, and
 * it is already keyed to the same anchor. Busy just runs it on a loop instead of
 * once, slower and linear: the hover sweep is a flourish and eases, a progress
 * signal is a metronome and should not. One hook, two treatments, using the
 * distinction the file already draws. */
body.app-busy .img-logo-a:not(:has(.img-logo-svg))::after {
    animation: lhq-logo-sweep 1.1s linear infinite;
}

@keyframes lhq-logo-sweep {
    from { transform: translateX(-130%); }
    to   { transform: translateX(130%); }
}

/* --- the inlined lockup --------------------------------------------------- */
.img-logo-a .img-logo-svg {
    height: 32px;
    width: auto;
    overflow: visible;
}
/* The lockup does not lift. The climber is the gesture; moving the whole thing as
   well would be a second one on top of it. */
.img-logo-a:hover .img-logo-svg {
    transform: none;
}

/* Less movement asked for: the raster lift and sweep stop. The falling ball's
   own guard is in the generated block below. */
@media (prefers-reduced-motion: reduce) {
    .img-logo-a .img-logo { transition: none; }
    .img-logo-a:hover .img-logo { transform: none; }
    .img-logo-a:hover::after,
    body.app-busy .img-logo-a::after { animation: none; }
}

/* ===== GENERATED by Planning/steps/lhq-logo-build.js =====================
   Everything down to the END marker is written by that file; edit it there.

   THE FALLING BALL. On hover, and while the app is busy (body.app-busy, set by
   appMain.busy() in main.js), a ball falls onto the logo's top step, bounces
   down one, two, three and drops through the floor, and the next one is
   already falling in at the top -- an indeterminate loop with no seam, which
   is what a "something is happening" signal needs to be. Each step lights up
   as the ball lands on it.

   The path is a SIMULATION (Planning/steps/logoPhysics.js), sampled into the
   keyframes below: true parabolas between bounces, each bounce keeping only
   part of its speed, squash scaled by how hard it lands, and a check that the
   ball never overlaps a step. The light is timed from the same landings.

   ONE DEFINITION FOR EVERY SURFACE. The top bar's logo, the rail's mark, the
   designed storefront's credit and the undesigned one's all carry the same
   markup, so they are all listed here rather than each restating the rules.
   This file is in both bundles, so it reaches every one of them.

   The ball and the lights are hidden by opacity ATTRIBUTES in the markup;
   these rules only ever reveal them, so an <img> of the logo stays still. */
:root { --lhq-fall: 2.221s; }

.lhq-ball { transform-box: fill-box; transform-origin: 50% 100%; }

/* The ball falls in from above the box and leaves through a strip to its
   left, so nothing that holds the mark may clip it. */
.img-logo-a:has(.img-logo-svg),
.v2-front .foot-by svg,
.store-credit .sc-by svg { overflow: visible; }

/* The ball is white, which is right on the top bar and the rail. A store's
   footer can be light (its Footer setting, Plain or Banded on a light page),
   so there the ball takes the credit's own text colour, the way LEARNERS
   does: light on a dark foot, dark on a light one. */
.v2-front .foot-by .lhq-ball,
.store-credit .sc-by .lhq-ball { fill: currentColor; }

.img-logo-a:hover .lhq-fall,
.sh-mark:hover .lhq-fall,
.v2-front .foot-by:hover .lhq-fall,
.store-credit .sc-by:hover .lhq-fall,
body.app-busy .img-logo-a .lhq-fall,
body.app-busy .sh-mark .lhq-fall { opacity: 1; }
.img-logo-a:hover .lhq-fall-p,
.sh-mark:hover .lhq-fall-p,
.v2-front .foot-by:hover .lhq-fall-p,
.store-credit .sc-by:hover .lhq-fall-p,
body.app-busy .img-logo-a .lhq-fall-p,
body.app-busy .sh-mark .lhq-fall-p { animation: lhq-fall-p var(--lhq-fall) linear infinite; }
.img-logo-a:hover .lhq-ball,
.sh-mark:hover .lhq-ball,
.v2-front .foot-by:hover .lhq-ball,
.store-credit .sc-by:hover .lhq-ball,
body.app-busy .img-logo-a .lhq-ball,
body.app-busy .sh-mark .lhq-ball { animation: lhq-fall-s var(--lhq-fall) linear infinite; }
.img-logo-a:hover .lhq-lit-top,
.sh-mark:hover .lhq-lit-top,
.v2-front .foot-by:hover .lhq-lit-top,
.store-credit .sc-by:hover .lhq-lit-top,
body.app-busy .img-logo-a .lhq-lit-top,
body.app-busy .sh-mark .lhq-lit-top { animation: lhq-lit-top var(--lhq-fall) linear infinite; }
.img-logo-a:hover .lhq-lit-mid,
.sh-mark:hover .lhq-lit-mid,
.v2-front .foot-by:hover .lhq-lit-mid,
.store-credit .sc-by:hover .lhq-lit-mid,
body.app-busy .img-logo-a .lhq-lit-mid,
body.app-busy .sh-mark .lhq-lit-mid { animation: lhq-lit-mid var(--lhq-fall) linear infinite; }
.img-logo-a:hover .lhq-lit-bot,
.sh-mark:hover .lhq-lit-bot,
.v2-front .foot-by:hover .lhq-lit-bot,
.store-credit .sc-by:hover .lhq-lit-bot,
body.app-busy .img-logo-a .lhq-lit-bot,
body.app-busy .sh-mark .lhq-lit-bot { animation: lhq-lit-bot var(--lhq-fall) linear infinite; }

@keyframes lhq-fall-p { 0% { transform:translate(53.20px,-1.50px); } 0.593% { transform:translate(52.87px,-0.96px); } 1.186% { transform:translate(52.53px,-0.37px); } 1.779% { transform:translate(52.20px,0.26px); } 2.372% { transform:translate(51.86px,0.94px); } 2.965% { transform:translate(51.53px,1.67px); } 3.558% { transform:translate(51.19px,2.43px); } 4.151% { transform:translate(50.86px,3.25px); } 4.744% { transform:translate(50.52px,4.11px); } 5.337% { transform:translate(50.19px,5.01px); } 5.93% { transform:translate(49.85px,5.96px); } 6.523% { transform:translate(49.52px,6.95px); } 7.116% { transform:translate(49.18px,7.99px); } 7.709% { transform:translate(48.85px,9.08px); } 8.302% { transform:translate(48.51px,10.21px); } 8.895% { transform:translate(48.18px,11.38px); } 9.44% { transform:translate(47.87px,12.50px); } 11.148% { transform:translate(47.87px,12.50px); } 11.195% { transform:translate(47.84px,12.44px); } 11.788% { transform:translate(47.51px,11.78px); } 12.381% { transform:translate(47.17px,11.16px); } 12.974% { transform:translate(46.84px,10.58px); } 13.567% { transform:translate(46.50px,10.05px); } 14.16% { transform:translate(46.17px,9.56px); } 14.753% { transform:translate(45.83px,9.12px); } 15.346% { transform:translate(45.50px,8.72px); } 15.939% { transform:translate(45.16px,8.37px); } 16.532% { transform:translate(44.83px,8.06px); } 17.125% { transform:translate(44.49px,7.80px); } 17.718% { transform:translate(44.16px,7.58px); } 18.311% { transform:translate(43.82px,7.41px); } 18.904% { transform:translate(43.49px,7.29px); } 19.497% { transform:translate(43.15px,7.21px); } 20.09% { transform:translate(42.82px,7.17px); } 20.683% { transform:translate(42.48px,7.18px); } 21.276% { transform:translate(42.15px,7.23px); } 21.869% { transform:translate(41.82px,7.33px); } 22.462% { transform:translate(41.48px,7.48px); } 23.055% { transform:translate(41.15px,7.67px); } 23.648% { transform:translate(40.81px,7.90px); } 24.241% { transform:translate(40.48px,8.18px); } 24.834% { transform:translate(40.14px,8.51px); } 25.427% { transform:translate(39.81px,8.88px); } 26.02% { transform:translate(39.47px,9.29px); } 26.613% { transform:translate(39.14px,9.75px); } 27.206% { transform:translate(38.80px,10.26px); } 27.799% { transform:translate(38.47px,10.81px); } 28.392% { transform:translate(38.13px,11.41px); } 28.985% { transform:translate(37.80px,12.05px); } 29.578% { transform:translate(37.46px,12.73px); } 30.171% { transform:translate(37.13px,13.46px); } 30.764% { transform:translate(36.79px,14.24px); } 31.357% { transform:translate(36.46px,15.06px); } 31.95% { transform:translate(36.12px,15.93px); } 32.543% { transform:translate(35.79px,16.84px); } 33.136% { transform:translate(35.45px,17.80px); } 33.729% { transform:translate(35.12px,18.80px); } 34.322% { transform:translate(34.78px,19.85px); } 34.915% { transform:translate(34.45px,20.94px); } 35.508% { transform:translate(34.11px,22.08px); } 36.101% { transform:translate(33.78px,23.26px); } 36.694% { transform:translate(33.44px,24.49px); } 37.287% { transform:translate(33.11px,25.76px); } 37.88% { transform:translate(32.77px,27.08px); } 38.472% { transform:translate(32.44px,28.44px); } 38.499% { transform:translate(32.42px,28.50px); } 40.207% { transform:translate(32.42px,28.50px); } 40.773% { transform:translate(32.10px,27.78px); } 41.366% { transform:translate(31.77px,27.07px); } 41.959% { transform:translate(31.43px,26.40px); } 42.552% { transform:translate(31.10px,25.78px); } 43.145% { transform:translate(30.77px,25.20px); } 43.738% { transform:translate(30.43px,24.67px); } 44.331% { transform:translate(30.10px,24.19px); } 44.924% { transform:translate(29.76px,23.75px); } 45.517% { transform:translate(29.43px,23.35px); } 46.11% { transform:translate(29.09px,23.00px); } 46.703% { transform:translate(28.76px,22.70px); } 47.296% { transform:translate(28.42px,22.44px); } 47.889% { transform:translate(28.09px,22.22px); } 48.482% { transform:translate(27.75px,22.05px); } 49.075% { transform:translate(27.42px,21.93px); } 49.668% { transform:translate(27.08px,21.85px); } 50.261% { transform:translate(26.75px,21.81px); } 50.854% { transform:translate(26.41px,21.82px); } 51.447% { transform:translate(26.08px,21.88px); } 52.04% { transform:translate(25.74px,21.98px); } 52.633% { transform:translate(25.41px,22.13px); } 53.226% { transform:translate(25.07px,22.32px); } 53.819% { transform:translate(24.74px,22.55px); } 54.412% { transform:translate(24.40px,22.83px); } 55.005% { transform:translate(24.07px,23.16px); } 55.598% { transform:translate(23.73px,23.53px); } 56.191% { transform:translate(23.40px,23.95px); } 56.784% { transform:translate(23.06px,24.41px); } 57.377% { transform:translate(22.73px,24.92px); } 57.97% { transform:translate(22.39px,25.47px); } 58.563% { transform:translate(22.06px,26.07px); } 59.156% { transform:translate(21.72px,26.71px); } 59.749% { transform:translate(21.39px,27.40px); } 60.342% { transform:translate(21.05px,28.13px); } 60.935% { transform:translate(20.72px,28.91px); } 61.528% { transform:translate(20.38px,29.73px); } 62.12% { transform:translate(20.05px,30.60px); } 62.713% { transform:translate(19.72px,31.51px); } 63.306% { transform:translate(19.38px,32.47px); } 63.899% { transform:translate(19.05px,33.47px); } 64.492% { transform:translate(18.71px,34.52px); } 65.085% { transform:translate(18.38px,35.61px); } 65.678% { transform:translate(18.04px,36.75px); } 66.271% { transform:translate(17.71px,37.93px); } 66.864% { transform:translate(17.37px,39.16px); } 67.457% { transform:translate(17.04px,40.44px); } 67.487% { transform:translate(17.02px,40.50px); } 69.194% { transform:translate(17.02px,40.50px); } 69.758% { transform:translate(16.70px,39.83px); } 70.351% { transform:translate(16.37px,39.17px); } 70.944% { transform:translate(16.03px,38.55px); } 71.537% { transform:translate(15.70px,37.98px); } 72.13% { transform:translate(15.36px,37.45px); } 72.723% { transform:translate(15.03px,36.97px); } 73.316% { transform:translate(14.69px,36.54px); } 73.909% { transform:translate(14.36px,36.14px); } 74.502% { transform:translate(14.02px,35.80px); } 75.095% { transform:translate(13.69px,35.50px); } 75.688% { transform:translate(13.35px,35.24px); } 76.281% { transform:translate(13.02px,35.03px); } 76.874% { transform:translate(12.68px,34.87px); } 77.467% { transform:translate(12.35px,34.75px); } 78.06% { transform:translate(12.01px,34.67px); } 78.653% { transform:translate(11.68px,34.64px); } 79.246% { transform:translate(11.34px,34.65px); } 79.839% { transform:translate(11.01px,34.71px); } 80.432% { transform:translate(10.67px,34.82px); } 81.025% { transform:translate(10.34px,34.97px); } 81.618% { transform:translate(10.00px,35.17px); } 82.211% { transform:translate(9.67px,35.41px); } 82.804% { transform:translate(9.33px,35.69px); } 83.397% { transform:translate(9.00px,36.02px); } 83.99% { transform:translate(8.67px,36.40px); } 84.583% { transform:translate(8.33px,36.82px); } 85.176% { transform:translate(8.00px,37.29px); } 85.769% { transform:translate(7.66px,37.80px); } 86.361% { transform:translate(7.33px,38.35px); } 86.954% { transform:translate(6.99px,38.95px); } 87.547% { transform:translate(6.66px,39.60px); } 88.14% { transform:translate(6.32px,40.29px); } 88.733% { transform:translate(5.99px,41.03px); } 89.326% { transform:translate(5.65px,41.81px); } 89.919% { transform:translate(5.32px,42.64px); } 90.512% { transform:translate(4.98px,43.51px); } 91.105% { transform:translate(4.65px,44.43px); } 91.698% { transform:translate(4.31px,45.39px); } 92.291% { transform:translate(3.98px,46.40px); } 92.884% { transform:translate(3.64px,47.45px); } 93.477% { transform:translate(3.31px,48.55px); } 94.07% { transform:translate(2.97px,49.69px); } 94.663% { transform:translate(2.64px,50.88px); } 95.256% { transform:translate(2.30px,52.11px); } 95.849% { transform:translate(1.97px,53.39px); } 96.442% { transform:translate(1.63px,54.71px); } 97.035% { transform:translate(1.30px,56.08px); } 97.628% { transform:translate(0.96px,57.49px); } 98.221% { transform:translate(0.63px,58.95px); } 98.814% { transform:translate(0.29px,60.46px); } 99.407% { transform:translate(-0.04px,62.01px); } 100% { transform:translate(-0.38px,63.60px); } }
@keyframes lhq-fall-s { 0% { transform:scale(0.940,1.084); } 7.543% { transform:scale(0.942,1.071); } 9.44% { transform:scale(1.000,1.000); } 10.294% { transform:scale(1.322,0.678); } 11.148% { transform:scale(1.097,0.903); } 13.994% { transform:scale(0.974,1.032); } 17.789% { transform:scale(1.000,1.000); } 36.601% { transform:scale(0.935,1.079); } 38.499% { transform:scale(1.000,1.000); } 39.353% { transform:scale(1.360,0.640); } 40.207% { transform:scale(1.108,0.892); } 43.053% { transform:scale(0.971,1.036); } 46.848% { transform:scale(1.000,1.000); } 65.589% { transform:scale(0.939,1.074); } 67.487% { transform:scale(1.000,1.000); } 68.341% { transform:scale(1.337,0.663); } 69.194% { transform:scale(1.101,0.899); } 72.041% { transform:scale(0.973,1.034); } 75.836% { transform:scale(1.000,1.000); } 100% { transform:scale(0.940,1.084); } }
@keyframes lhq-lit-top { 0%, 9.24% { opacity: 0; } 9.44%, 16.70% { opacity: 1; } 38.50%, 100% { opacity: 0; } }
@keyframes lhq-lit-mid { 0%, 38.30% { opacity: 0; } 38.50%, 45.75% { opacity: 1; } 67.49%, 100% { opacity: 0; } }
@keyframes lhq-lit-bot { 0%, 67.29% { opacity: 0; } 67.49%, 74.73% { opacity: 1; } 96.47%, 100% { opacity: 0; } }

/* A TAP IS NOT A HOVER. A tap synthesises :hover and nothing takes it away, so
   the ball would start on a tap and keep falling -- which reads as "the app is
   busy", because that is what the same loop means. Only the hover half is put
   back: every busy selector carries body in front and so outweighs these. */
@media (hover: none) {
.img-logo-a:hover .lhq-fall,
.sh-mark:hover .lhq-fall,
.v2-front .foot-by:hover .lhq-fall,
.store-credit .sc-by:hover .lhq-fall { opacity: 0; }
.img-logo-a:hover .lhq-fall-p,
.sh-mark:hover .lhq-fall-p,
.v2-front .foot-by:hover .lhq-fall-p,
.store-credit .sc-by:hover .lhq-fall-p,
.img-logo-a:hover .lhq-ball,
.sh-mark:hover .lhq-ball,
.v2-front .foot-by:hover .lhq-ball,
.store-credit .sc-by:hover .lhq-ball,
.img-logo-a:hover .lhq-lit rect,
.sh-mark:hover .lhq-lit rect,
.v2-front .foot-by:hover .lhq-lit rect,
.store-credit .sc-by:hover .lhq-lit rect { animation: none; }
}

/* Less movement asked for: the mark stays as drawn and nothing runs, busy
   included -- that one starts on its own, which is exactly what the setting
   exists to stop. PACE's bar across the top still says the page is working. */
@media (prefers-reduced-motion: reduce) {
    .lhq-fall { opacity: 0 !important; }
    .lhq-fall-p, .lhq-ball, .lhq-lit rect { animation: none !important; }
}
/* ===== END GENERATED ===================================================== */

/* ---------------------------------------------------------------------------
   PHONES: THE WHOLE LOCKUP, SCALED TO FIT.

   Measured at 386px before this: the anchor was 139px, the lockup rendered at
   185px, and the anchor's overflow:hidden ate the last 46 -- a quarter of the
   logo, so the wordmark stopped mid-letter. A truncated logo reads as broken
   rather than as a compact treatment, and it is the clipping that was wrong,
   not the width.

   The theme's own answer was to drop the logo entirely below 579 and give the
   width to the search box, then below 500 bring it back and move search into a
   button. An honest trade, but it left the logo missing between 501 and 579 --
   measured, gone at 520, 540 and 575 -- and shrinking the lockup avoids having
   to make the trade at all.

   WIDTH IS NOT SET HERE, height is. The lockup is 643.4 x 111.5, so its width
   follows from its height at 5.77:1, and the anchor is width:auto so it takes
   whatever that comes to. Setting both is how the clipping happened in the
   first place: a fixed anchor narrower than the drawing it holds.

   26px of height puts the lockup at 150, which clears the widest the icons get
   once they are at their 44px tap size. Below 380 there is no longer room for
   that, so it steps down again rather than being clipped.
   --------------------------------------------------------------------------- */
@media (max-width: 767px) {
    .img-logo-a {
        width: auto;
        margin: 0;
        padding: 0;
        /* The logo is a link to the dashboard, so it gets the same 44px floor as
           every other control -- on the height, since 150px of width was never
           the problem. The anchor is already inline-flex and centred, so the
           drawing sits in the middle of the taller box rather than moving. */
        min-height: 44px;
        /* Do not let flex squeeze it. The anchor is a flex item on the bar, so
           width:auto still shrinks under pressure -- measured 136px holding a
           150px drawing, clipped by 14 -- and the anchor clips rather than
           scales. Refusing to shrink is what makes the height above the only
           thing deciding the size. */
        flex: 0 0 auto;
    }
    .img-logo-a .img-logo-svg {
        height: 26px;
    }
}
@media (max-width: 379px) {
    .img-logo-a .img-logo-svg {
        height: 22px;
    }
}

/* ---------------------------------------------------------------------------
   THE LOGO'S HOVER ANIMATIONS DO NOT RUN ON A TOUCHSCREEN.

   Same fault the rail glow had. A tap synthesises :hover and nothing takes it
   away until you touch something else, so the climber would start on a tap and
   keep running -- a logo animating by itself, with no cursor anywhere near it,
   which on this logo reads as "the app is busy" because that is exactly what
   the same animation means.

   THE BUSY STATE IS UNAFFECTED, and that is the point of resetting rather than
   wrapping the originals in @media (hover: hover). Every rule here matches at
   (0,3,0) or (0,3,1); its body.app-busy counterpart is one higher, because of
   the `body` in front. So when the app is genuinely working the climber still
   runs on a phone, and only the hover half is put back.
   --------------------------------------------------------------------------- */
@media (hover: none) {
    /* The lift. */
    .img-logo-a:hover .img-logo {
        transform: none;
    }
    /* The sweep, for an account whose logo is a raster and has no climber. */
    .img-logo-a:not(:has(.img-logo-svg)):hover::after {
        animation: none;
    }
    /* The falling ball's own tap guard is in the generated block. */
}

/* ---- between pages ---------------------------------------------------------
   The other half of the loading signal (Martin, 30 Sep 2026). Moving around
   the platform is a full page load, and it used to arrive as three jolts: the
   old page went, a half-built one appeared, and the screen popped in after.
   header.tpl and header_public.tpl now hold the first paint until the screen
   is built; this crossfades the old page into the finished one.

   The rail and the top bar are named, so Chrome carries each across as the
   same object instead of fading it out and back in -- the frame stays put and
   only the page inside it changes. The top bar SWAPS rather than blends: its
   slabs are never at the same phase on two pages, and two of them blended
   read as a double exposure. The new page settles downwards a few pixels, the
   way the slabs move.

   In this file because logo.css is in both bundles, and a crossfade only
   happens when both pages ask for one. Browsers without view transitions
   ignore all of it and load pages exactly as before. */
@view-transition {
    navigation: auto;
}

body.v2 .sh-rail {
    view-transition-name: lhq-rail;
}

/* THE BAR'S PIECES ARE NAMED, NOT THE BAR. A named element is its own
   stacking context, always, not only during a change -- and naming .sh-top
   trapped the cluster and the store picker (z-index 60, so their menus clear
   the page) at the header's own level, under anything positioned after it.
   On the marketplace, whose wrapper is positioned and painted solid, the whole
   bar vanished behind the page (Martin, 30 Sep). Each piece named here is
   ALREADY a stacking context -- positioned with a z-index in v2.css -- so the
   names change nothing about how the bar stacks. The rail is the same: fixed
   at z-index 50. Hidden pieces (the upgrade link for a creator) are skipped
   by Chrome. */
body.v2 .sh-plate { view-transition-name: lhq-plate; view-transition-class: lhq-hold; }
body.v2 .sh-storewrap { view-transition-name: lhq-store; view-transition-class: lhq-hold; }
body.v2 .sh-upgrade { view-transition-name: lhq-upgrade; view-transition-class: lhq-hold; }
body.v2 .sh-ribwrap { view-transition-name: lhq-slabs; view-transition-class: lhq-hold; }
body.v2 .sh-right { view-transition-name: lhq-cluster; view-transition-class: lhq-hold; }

/* The old page does NOT fade. It used to, faster than the new one came in,
   so for a moment both were half transparent and the background showed
   through between them -- the blink Martin still saw. Held solid underneath,
   there is always a whole page on screen, and the new one covers it. */
::view-transition-old(root) {
    animation: none;
}

::view-transition-new(root) {
    animation: 260ms cubic-bezier(.2, .7, .3, 1) both lhq-page-in;
}

/* The OLD bar is the one held through the change, and the live one takes
   over when it ends. The other way round, the first frame of the new page
   was what showed -- and in that frame the slabs are not drawn yet (their
   script starts at DOMContentLoaded) and the profile picture may still be
   decoding, so the bar blinked half empty (Martin, 30 Sep). 260ms later
   both are there, and the slabs pick up from where the old bar left them. */
::view-transition-old(*.lhq-hold) {
    animation: none;
}

::view-transition-new(*.lhq-hold) {
    animation: none;
    opacity: 0;
}

@keyframes lhq-page-in {
    from { opacity: 0; transform: translateY(-6px); }
}

@media (prefers-reduced-motion: reduce) {
    ::view-transition-group(*),
    ::view-transition-old(*),
    ::view-transition-new(*) {
        animation: none !important;
    }
}
/* ---------------------------------------------------------------------------
   THE FOOTER, ONE DESIGN FOR EVERY PAGE THAT HAS ONE (26 September 2026).

   There were two: a faint grey line of capitals inside the app (footer.tpl)
   and a solid teal bar of white capitals on public pages (built in
   Output::render()). Martin asked for one, cohesive, in the stripped-back
   look the rail now has. Both places now print the same markup from
   Output::footerBar(), and this file dresses it.

   Loaded by BOTH dynamic bundles (dynamic.php and public_dynamic.php), like
   logo.css, because the footer is on both kinds of page. That is also why
   every colour is var(--token, fallback): a public page does not carry the
   v2 :root tokens, so the fallback is the canon value itself.

   NEW CLASS NAMES ON PURPOSE. main.css and public.css both style .footer
   (padding, a fill, fixed variants). Keeping the old name would have meant
   winning an argument with each of them on every property; a new name has
   nothing to argue with.

   Also here: the footer's own pages when they open inside the app
   (.lhq-doc -- Privacy and Terms, see Pages::registeredRoutes()), and the
   back-to-top button, which sat on top of "Contact us".
   --------------------------------------------------------------------------- */

.lhq-foot { border-top:1px solid var(--line, rgba(255,255,255,.09)); background:transparent;
  margin-top:40px; font-family:"Lato", Helvetica, Arial, sans-serif; }
/* 84px on the right is the back-to-top button's lane (47 wide, 20 off the
   edge, and room to breathe): moved bottom-right below, it would otherwise
   land on the last link instead of the middle one. */
.lhq-foot-in { max-width:1320px; margin:0 auto; padding:18px 84px 22px 20px; display:flex;
  align-items:center; justify-content:space-between; flex-wrap:wrap; gap:12px 28px; }

.lhq-foot-id { display:flex; align-items:center; gap:10px; margin:0;
  color:var(--dim, #6f7885); font-size:12px; font-variant-numeric:tabular-nums; }
.lhq-foot-mark { width:15px; height:15px; display:block; flex:none; }
/* The full logo (28 Sep 2026): LEARNERS in white, HQ in blue, the green mark
   before it, at the height of a line of footer text. */
.lhq-foot .lhq-foot-logo { display:block; flex:none; height:16px; width:auto; max-width:none; }

.lhq-foot-links { list-style:none; margin:0; padding:0; display:flex; flex-wrap:wrap;
  align-items:center; gap:6px 22px; }
.lhq-foot-links li { margin:0; padding:0; }
/* Grey at rest, the HQ blue under the pointer -- the rail's own rule, so the
   two edges of the screen behave the same way. */
.lhq-foot .lhq-foot-links a { color:var(--muted, #98a1ad); font-size:12.5px; font-weight:400;
  letter-spacing:0; text-transform:none; text-decoration:none; transition:color .15s; }
.lhq-foot .lhq-foot-links a:hover { color:var(--brand, #2563eb); text-decoration:none; }
.lhq-foot .lhq-foot-links a:focus-visible { color:var(--brand, #2563eb); outline:2px solid var(--brand, #2563eb);
  outline-offset:3px; border-radius:2px; }
/* The one action in the footer, so it is the green one. Only printed for
   somebody who can take it: logged out, or a customer. */
.lhq-foot .lhq-foot-links a.lhq-foot-go { color:var(--green-lit, #3ad47a); font-weight:700; }
.lhq-foot .lhq-foot-links a.lhq-foot-go:hover { color:var(--green-lit, #3ad47a); text-decoration:underline; }

/* "Prices in" for a visitor (2 Oct 2026): the currency their prices are shown
   in, quiet like the links beside it. Output::currencyPicker(), in our footer
   and in a store's own (.foot, V2StorefrontComponents::foot -- where it sits
   on the right, before the links). public.js answers it. */
.lhq-foot .lhq-foot-cur, .foot .lhq-foot-cur { display:flex; align-items:center; gap:6px; margin:0; color:var(--muted, #98a1ad);
  font-size:12.5px; font-weight:400; }
.foot .lhq-foot-cur { margin-left:auto; }
.lhq-foot .lhq-foot-cur select, .foot .lhq-foot-cur select { height:28px; padding:0 6px; border-radius:7px;
  border:1px solid var(--line, #31363d); background:var(--ground, #1c1c1c); color:var(--text, #e9edf2);
  font:inherit; font-size:12.5px; color-scheme:dark; }
.lhq-foot .lhq-foot-cur select:focus, .foot .lhq-foot-cur select:focus { outline:none; border-color:var(--brand, #2563eb); }

@media (max-width:640px) {
  .lhq-foot-in { flex-direction:column; justify-content:center; text-align:center;
    padding-right:20px; padding-bottom:72px; }  /* room for the back-to-top button below the links */
  .lhq-foot-links { justify-content:center; }
}

/* THE BACK-TO-TOP BUTTON, bottom right at every width. ui.totop.css puts it
   at left:52% and dashboard.css pins it at the centre with !important, which
   is the footer's middle -- it covered "Contact us". chrome.css already moved
   it right below 768px; this does it everywhere. The id plus two elements is
   what outranks dashboard.css's own !important. */
html body #toTop { left:auto !important; right:20px !important; margin:0 !important; bottom:20px; }

/* ---- the footer's pages: Privacy, Terms, Contact --------------------------
   Rebuilt 27 September 2026 (Martin: "more in line with the current design
   fully ... accordions perhaps for those lengthy policies"). Their markup is
   modules/Pages/tpl/doc_*.tpl, rendered in place of the old CMS content, and
   it is the same page logged in (inside the app) and logged out (public
   chrome) -- which is why this lives here, in the one sheet both bundles load,
   and why every colour carries its canon value as the fallback.

   The canon's grammar throughout: an uppercase eyebrow, a 25/900 title, one
   muted sentence under it; a single card for the one thing set apart (the
   short version, the form); green for the one action; the HQ blue under the
   pointer and green for what is open, exactly as the rail does it. */
body .lhq-doc { max-width:820px; margin:0 auto; padding:8px 20px 8px;
  font-family:"Lato", Helvetica, Arial, sans-serif; font-size:14.5px; line-height:1.65;
  color:var(--muted, #98a1ad); }
body .lhq-doc.lhq-doc-wide { max-width:1040px; }
/* Inside the app the 50px top bar lies over the page and the back strip sits
   in its row, so the eyebrow at 48px was under the bar's lower edge. */
body.v2 .lhq-doc { padding-top:30px; }
.lhq-docpage { display:flex; flex-direction:column; gap:24px; }

.lhq-doc-head { display:flex; flex-direction:column; gap:8px; padding-top:10px; }
.lhq-doc .lhq-doc-eyebrow { margin:0; font-size:11.5px; font-weight:700; letter-spacing:.09em;
  text-transform:uppercase; color:var(--dim, #6f7885); }
body .lhq-doc h1.lhq-doc-title { margin:0; font-family:inherit; font-size:25px; font-weight:900;
  letter-spacing:-.015em; line-height:1.2; color:var(--text, #e9edf2); text-transform:none; text-wrap:balance; }
.lhq-doc .lhq-doc-meta { margin:0; font-size:12px; color:var(--dim, #6f7885); font-variant-numeric:tabular-nums; }
.lhq-doc .lhq-doc-lede { margin:0; font-size:15px; color:var(--muted, #98a1ad); max-width:64ch; }

.lhq-doc a { color:var(--brand, #2563eb); text-decoration:underline; text-underline-offset:2px; }
.lhq-doc a:hover { color:var(--brand, #2563eb); text-decoration-thickness:2px; }
.lhq-doc a:focus-visible { outline:2px solid var(--brand, #2563eb); outline-offset:2px; border-radius:2px; }
.lhq-doc strong { color:var(--text, #e9edf2); font-weight:700; }

/* The short version: the one card on a policy page. */
.lhq-doc-short { background:var(--panel, #2a2a2a); border:1px solid var(--line, rgba(255,255,255,.09));
  border-radius:8px; padding:16px 20px; }
body .lhq-doc .lhq-doc-short h2 { margin:0 0 10px; font-family:inherit; font-size:11.5px; font-weight:700;
  letter-spacing:.09em; text-transform:uppercase; color:var(--dim, #6f7885); }
.lhq-doc-short ul { margin:0; padding-left:18px; display:flex; flex-direction:column; gap:6px; }
.lhq-doc-short li { margin:0; color:var(--text, #e9edf2); font-size:14px; line-height:1.55; }

.lhq-doc-tools { display:flex; align-items:center; justify-content:space-between; gap:12px; }
.lhq-doc-all { font:700 11.5px/1 "Lato", Helvetica, Arial, sans-serif; letter-spacing:.07em; text-transform:uppercase;
  color:var(--text, #e9edf2); background:transparent; border:1px solid rgba(255,255,255,.18);
  border-radius:6px; padding:8px 12px; cursor:pointer; }
.lhq-doc-all:hover { border-color:rgba(255,255,255,.34); }
.lhq-doc-all:focus-visible { outline:2px solid var(--brand, #2563eb); outline-offset:2px; }
.lhq-doc-all[hidden] { display:none; }

/* The accordion. Native <details>; lhq-docs.js only adds Expand all and
   opening the section a #link names. */
.lhq-acc { border-top:1px solid var(--line, rgba(255,255,255,.09)); }
.lhq-acc-item { border-bottom:1px solid var(--line, rgba(255,255,255,.09)); scroll-margin-top:70px; }
.lhq-acc-item > summary { list-style:none; cursor:pointer; display:flex; align-items:center; gap:14px;
  padding:15px 4px; border-radius:4px; }
.lhq-acc-item > summary::-webkit-details-marker { display:none; }
.lhq-acc-item > summary::marker { content:""; }
.lhq-acc-item > summary .n { width:22px; flex:none; color:var(--dim, #6f7885); font-size:12px; font-weight:700;
  font-variant-numeric:tabular-nums; transition:color .15s; }
.lhq-acc-item > summary .t { flex:1; min-width:0; color:var(--text, #e9edf2); font-size:15px; font-weight:700;
  line-height:1.35; transition:color .15s; }
.lhq-acc-item > summary .chev { width:16px; height:16px; flex:none; color:var(--dim, #6f7885);
  transition:transform .2s ease, color .15s; }
.lhq-acc-item > summary:hover .t, .lhq-acc-item > summary:hover .chev { color:var(--brand, #2563eb); }
.lhq-acc-item > summary:focus-visible { outline:2px solid var(--brand, #2563eb); outline-offset:2px; }
.lhq-acc-item[open] > summary .chev { transform:rotate(90deg); color:var(--green-lit, #3ad47a); }
.lhq-acc-item[open] > summary .n { color:var(--green-lit, #3ad47a); }
.lhq-acc-body { padding:0 4px 20px 40px; }
.lhq-acc-body > :last-child { margin-bottom:0; }
.lhq-doc .lhq-acc-body p { margin:0 0 10px; }
body .lhq-doc .lhq-acc-body h3 { margin:18px 0 6px; font-family:inherit; font-size:13.5px; font-weight:700;
  line-height:1.4; color:var(--text, #e9edf2); }
.lhq-doc .lhq-acc-body ul, .lhq-doc .lhq-acc-body ol { margin:0 0 12px; padding-left:18px; }
.lhq-doc .lhq-acc-body li { margin:0 0 6px; }
.lhq-doc .lhq-doc-end { margin:0; font-size:13.5px; color:var(--muted, #98a1ad); }
@media (max-width:640px) {
  .lhq-acc-body { padding-left:4px; }
  .lhq-acc-item > summary { gap:10px; }
}
@media (prefers-reduced-motion:reduce) { .lhq-acc-item > summary .chev { transition:none; } }

/* ---- Contact ------------------------------------------------------------- */
.lhq-contact-grid { display:grid; grid-template-columns:minmax(0, 1.7fr) minmax(0, 1fr); gap:28px; align-items:start; }
.lhq-contact, .lhq-contact-done { background:var(--panel, #2a2a2a); border:1px solid var(--line, rgba(255,255,255,.09));
  border-radius:8px; padding:22px; display:flex; flex-direction:column; gap:16px; margin:0; }
.lhq-contact[hidden], .lhq-contact-done[hidden] { display:none; }
.lhq-contact-row { display:grid; grid-template-columns:1fr 1fr; gap:16px; }
.lhq-field { display:flex; flex-direction:column; gap:6px; min-width:0; }
.lhq-doc .lhq-field label { margin:0; font-size:11.5px; font-weight:700; letter-spacing:.07em;
  text-transform:uppercase; color:var(--muted, #98a1ad); }
.lhq-field label .opt { font-weight:400; letter-spacing:0; text-transform:none; color:var(--dim, #6f7885); }
.lhq-doc .lhq-field input, .lhq-doc .lhq-field select, .lhq-doc .lhq-field textarea {
  width:100%; box-sizing:border-box; height:auto; margin:0; font:14px/1.4 "Lato", Helvetica, Arial, sans-serif;
  color:var(--text, #e9edf2); background:var(--ground, #1c1c1c); border:1px solid rgba(255,255,255,.14);
  border-radius:6px; padding:10px 12px; box-shadow:none; color-scheme:dark; transition:border-color .15s, box-shadow .15s; }
.lhq-doc .lhq-field textarea { min-height:160px; resize:vertical; line-height:1.55; }
.lhq-doc .lhq-field ::placeholder { color:var(--dim, #6f7885); opacity:1; }
.lhq-doc .lhq-field input:focus, .lhq-doc .lhq-field select:focus, .lhq-doc .lhq-field textarea:focus {
  outline:none; border-color:var(--brand, #2563eb); box-shadow:0 0 0 3px rgba(37,99,235,.25); }
.lhq-doc .lhq-field [aria-invalid="true"] { border-color:var(--danger, #ed5565); }
.lhq-doc .lhq-err, .lhq-doc .lhq-contact-note { margin:0; font-size:12.5px; color:#f08d98; }
.lhq-err[hidden], .lhq-contact-note[hidden] { display:none; }
/* The bot trap: off screen rather than display:none, which some bots skip. */
.lhq-hp { position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden; }
.lhq-contact-foot { display:flex; align-items:center; justify-content:space-between; gap:12px 16px; flex-wrap:wrap; }
.lhq-doc .lhq-contact-small { margin:0; font-size:11.5px; line-height:1.5; color:var(--dim, #6f7885); max-width:46ch; }
.lhq-doc .lhq-contact-small a { color:var(--muted, #98a1ad); }
.lhq-contact-send { font:700 13.5px/1 "Lato", Helvetica, Arial, sans-serif; color:#fff; background:var(--green, #2dc26b);
  border:0; border-radius:6px; padding:12px 20px; cursor:pointer; transition:background .15s; }
.lhq-contact-send:hover { background:var(--green-lit, #3ad47a); }
.lhq-contact-send:focus-visible { outline:2px solid var(--brand, #2563eb); outline-offset:2px; }
.lhq-contact-send:disabled { opacity:.6; cursor:default; }
.lhq-contact-done:focus { outline:none; }
body .lhq-doc .lhq-contact-done h2 { margin:0; font-family:inherit; font-size:18px; font-weight:900; color:var(--text, #e9edf2); }
.lhq-doc .lhq-contact-done p { margin:0; }
.lhq-contact-again { align-self:flex-start; font:700 11.5px/1 "Lato", Helvetica, Arial, sans-serif; letter-spacing:.07em;
  text-transform:uppercase; color:var(--text, #e9edf2); background:transparent; border:1px solid rgba(255,255,255,.18);
  border-radius:6px; padding:9px 13px; cursor:pointer; }
.lhq-contact-again:hover { border-color:rgba(255,255,255,.34); }

.lhq-contact-aside { display:flex; flex-direction:column; gap:22px; padding-top:4px; }
.lhq-contact-aside section { display:flex; flex-direction:column; gap:8px; }
body .lhq-doc .lhq-contact-aside h2 { margin:0; font-family:inherit; font-size:11.5px; font-weight:700;
  letter-spacing:.09em; text-transform:uppercase; color:var(--dim, #6f7885); }
.lhq-contact-aside dl { margin:0; display:flex; flex-direction:column; gap:10px; }
.lhq-contact-aside dt { margin:0; font-size:13.5px; font-weight:700; color:var(--text, #e9edf2); }
.lhq-contact-aside dd { margin:0; font-size:13.5px; }
.lhq-doc .lhq-contact-aside p { margin:0; font-size:13.5px; }

/* Who you are, at the top of the form: logged in it names you, logged out
   it offers to log you in. */
.lhq-doc .lhq-contact-hint { margin:0; padding:0 0 14px; border-bottom:1px solid var(--line, rgba(255,255,255,.09));
  font-size:13.5px; color:var(--muted, #98a1ad); }
.lhq-doc .lhq-field-hint { margin:0; font-size:12px; color:var(--dim, #6f7885); }

/* Our channels. A channel with no address yet is not a link and says so;
   the main one, once chosen, goes first and is tagged in green. */
.lhq-socs { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:8px; }
.lhq-soc a, .lhq-soc .lhq-soc-in { display:flex; align-items:center; gap:10px; padding:9px 12px;
  border:1px solid var(--line, rgba(255,255,255,.09)); border-radius:8px; text-decoration:none;
  color:var(--text, #e9edf2); font-size:13.5px; font-weight:700; transition:border-color .15s, color .15s; }
.lhq-soc .ic { width:20px; height:20px; flex:none; display:grid; place-items:center; color:var(--muted, #98a1ad); }
.lhq-soc .ic svg { width:18px; height:18px; display:block; }
.lhq-soc .nm { flex:1; min-width:0; }
.lhq-soc a:hover { border-color:var(--brand, #2563eb); color:var(--text, #e9edf2); text-decoration:none; }
.lhq-soc a:hover .ic { color:var(--brand, #2563eb); }
.lhq-soc.is-main a { border-color:rgba(45,194,107,.45); }
.lhq-soc.is-main .ic { color:var(--green-lit, #3ad47a); }
.lhq-soc-tag { font-size:10.5px; font-weight:700; letter-spacing:.07em; text-transform:uppercase;
  color:var(--green-lit, #3ad47a); }
.lhq-soc.is-soon .lhq-soc-in { color:var(--muted, #98a1ad); border-style:dashed; }
.lhq-soc.is-soon .ic { color:var(--dim, #6f7885); }
.lhq-soc-soon { font-size:10.5px; font-weight:700; letter-spacing:.07em; text-transform:uppercase; color:var(--dim, #6f7885); }
.lhq-doc .lhq-soc-note { margin:2px 0 0; font-size:12px; color:var(--dim, #6f7885); }

/* The reCAPTCHA badge would sit on the back-to-top button in the corner.
   Google allows hiding it when the form carries its notice instead, which
   .lhq-contact-small does. */
body:has(.lhq-contact) .grecaptcha-badge { visibility:hidden; }

@media (max-width:760px) {
  .lhq-contact-grid { grid-template-columns:1fr; }
  .lhq-contact-row { grid-template-columns:1fr; }
}

/* ---- a store inside the app ------------------------------------------------
   A logged-in visitor sees a storefront inside the app shell, and the shell's
   top row (.sh-top: the store switcher, bell, messages, profile) floats over
   the top of every screen -- a negative bottom margin, so screens run up
   underneath it and leave that corner free. A storefront does not leave it
   free: its own header, name and tabs, runs the full width, and the two sat
   on top of each other (Martin, 27 Sep 2026, on ZenPower Academy).

   So on a store page the row stops floating and the store starts below it.
   Desktop only: below 780 the row is already a bar in the flow of the page
   (v2.css), and has no overlap to undo. Other screens keep the float.
   -------------------------------------------------------------------------- */
@media (min-width: 781px) {
    body.v2.offers-page .sh-top {
        margin-bottom: 12px;
    }
}

/* AND THE STORE STAYS OUT OF THE RAIL. courses.css (2016) gives
   #courses-content "margin: 0 -30px" to cancel padding the old page wrapper
   had. Inside the app shell the wrapper has none, so the store ran 10px under
   the rail and 20px past the right edge (Martin, 27 Sep 2026). Only store
   pages use #courses-content inside the app; logged out, the old wrapper and
   its padding are still there, so the -30px stays for them. */
body.v2.offers-page #courses-content {
    margin-left: 0;
    margin-right: 0;
}

/* ===========================================================================
   v2-follow.css -- the Follow button (28 Sep 2026) and the Following page.
   In both bundles, like its script. The storefront carries its own tokens
   (a store's colours); the fallbacks are the platform's, for pages without.
   =========================================================================== */
.lhq-follow-slot:empty { display:none; }
.lhq-follow { display:inline-flex; align-items:center; gap:6px; padding:7px 14px; border-radius:999px;
  border:1px solid var(--green, #2dc26b); background:var(--green, #2dc26b); color:#fff;
  font:inherit; font-size:13px; font-weight:700; line-height:1.2; cursor:pointer; text-decoration:none;
  transition:background .15s, border-color .15s, color .15s; white-space:nowrap; }
.lhq-follow:hover { background:var(--green-lit, #3ad47a); border-color:var(--green-lit, #3ad47a); color:#fff; text-decoration:none; }
.lhq-follow.is-on { background:transparent; border-color:var(--line, rgba(255,255,255,.18)); color:var(--text, #e9edf2); }
.lhq-follow.is-on:hover { border-color:var(--danger, #ed5565); color:#f08d98; background:transparent; }
.lhq-follow.is-on:hover span { font-size:0; }
.lhq-follow.is-on:hover span::after { content:"Unfollow"; font-size:13px; }
.lhq-follow:disabled { opacity:.6; cursor:default; }
.lhq-follow:focus-visible { outline:2px solid var(--brand, #2563eb); outline-offset:2px; }

/* Beside "Visit store" on a product page. */
.lhq-follow-pp { display:inline-flex; margin-left:10px; vertical-align:middle; }
.lhq-follow-pp .lhq-follow { padding:5px 11px; font-size:12px; }
/* In the byline, "from <the store>" (30 Sep 2026): a line of small text. */
.byline .lhq-follow-pp .lhq-follow { padding:3px 10px; font-size:11.5px; }
.lhq-follow-pp .lhq-follow.is-on:hover span::after { font-size:12px; }

.lhq-follow-toast { position:fixed; left:50%; bottom:24px; transform:translateX(-50%); z-index:100001;
  max-width:calc(100vw - 32px); padding:10px 16px; border-radius:10px; background:#272b31;
  border:1px solid rgba(255,255,255,.18); color:#e9edf2; font:700 13px/1.4 Lato, Helvetica, Arial, sans-serif;
  box-shadow:0 14px 34px rgba(0,0,0,.55); }

/* ---- the Following page ---- */
.v2-following .fl-list { max-width:760px; margin:0; padding:0; list-style:none; display:flex; flex-direction:column; gap:6px; }
.v2-following .fl-row { display:flex; align-items:center; gap:14px; padding:12px 14px; border-radius:12px;
  background:var(--panel); border:1px solid var(--line); }
.v2-following .fl-pic { flex:none; width:40px; height:40px; border-radius:50%; background:var(--panel-2) center/cover no-repeat;
  display:flex; align-items:center; justify-content:center; font-weight:900; color:#fff; }
.v2-following .fl-main { flex:1; min-width:0; display:flex; flex-direction:column; gap:3px; }
.v2-following .fl-main a { font-size:14.5px; font-weight:700; color:var(--text); text-decoration:none; }
.v2-following .fl-main a:hover { text-decoration:underline; }
.v2-following .fl-state { font-size:12px; color:var(--dim); }
.v2-following .fl-row.is-off .fl-main a { color:var(--muted); }
.v2-following .fl-acts { display:flex; gap:8px; flex:none; }
.v2-following .fl-acts button { padding:6px 12px; border-radius:8px; border:1px solid var(--line); background:transparent;
  color:var(--muted); font:inherit; font-size:12.5px; font-weight:700; cursor:pointer; }
.v2-following .fl-acts button:hover { color:var(--text); border-color:rgba(255,255,255,.22); }
.v2-following .fl-acts button[hidden] { display:none; }
.v2-following .fl-note { max-width:760px; font-size:12.5px; color:var(--dim); margin:14px 0 0; }
@media (max-width:640px) {
  .v2-following .fl-row { flex-wrap:wrap; }
  .v2-following .fl-acts { width:100%; justify-content:flex-end; }
}
/* The sale alerts switch above the list (28 Sep 2026). */
.v2-following .fl-alerts { max-width:760px; display:flex; align-items:flex-start; gap:12px; margin:0 0 18px; padding:14px 16px;
  border-radius:12px; background:var(--panel); border:1px solid var(--line); cursor:pointer; }
.v2-following .fl-alerts input { flex:none; margin:2px 0 0; width:16px; height:16px; accent-color:var(--green); }
.v2-following .fl-alerts > span { flex:1; display:flex; flex-direction:column; gap:3px; }
.v2-following .fl-alerts b { font-size:13.5px; color:var(--text); }
.v2-following .fl-alerts > span > span { font-size:12.5px; color:var(--dim); }
.v2-following .fl-alerts-said { flex:none; font-style:normal; font-size:12px; color:var(--green-lit); }

