/* ===========================================================================
 * Level Zero brand - THE START PAGE ONLY (`/`).
 *
 * Why this file exists at all, and why it is not branding/theme/levelzero.css:
 *
 * The start page is the one public surface with NO settings hook and NO
 * custom_css hook. presale/context.py falls through to GlobalSettingsObject()
 * for an eventless request and never sets `css_file`, and
 * common/base_public.html:82 gates custom_css on `current_event` - which the
 * start page does not have, because it is not even in that template chain
 * (its root is pretixpresale/startpage_base.html). Its only stylesheet is the
 * django-compressor bundle, COMPILED INTO THE IMAGE: in it,
 * `nav.navbar.navbar-inverse{background-color:#2185d0}` is a literal hex that
 * no setting anywhere can reach.
 *
 * So this file is linked by a TEMPLATE OVERRIDE of startpage_base.html
 * (customizations/templates/, recorded in customizations/OVERRIDES.tsv). It is
 * served by the `handle_path /static/brand/*` route already in
 * caddy/routing.caddy - no Caddy change, no compose change.
 *
 * ⚠ The remaining alternative was a plugin using the `global_html_head`
 *   signal, which is how `{{ html_head|safe }}` on that page is fed. Plugins
 *   are cut by constraint, so the override is the only route left.
 *
 * ⚠ The @font-face block below is DELIBERATELY DUPLICATED from
 *   levelzero.css. Do not "de-duplicate" it into a shared import: that file is
 *   uploaded whole into Event.custom_css and must stay self-contained, and an
 *   @import would cost an extra round trip on every page load.
 *
 * See docs/theming.md.
 * ======================================================================== */

/* --- 1. Faces. Same files, same route, as the event-page theme. ----------- */

/* Museo Sans - referenced with local() ONLY. There is deliberately no url().
 *
 * /!\ DO NOT ADD A url() SOURCE HERE. The Museo Sans files on the operator's
 *     Mac are a Fontspring DEMO (900) and two Adobe Fonts desktop-sync files
 *     (100/300 - they carry typekit.com/eulas/ in their name table). Neither
 *     licence covers serving the binary to visitors, which is exactly what a
 *     url() source does. local() ships nothing: the browser uses a copy the
 *     VIEWER already has installed, else falls through to Archivo below.
 *
 * /!\ So this is a DEV-SYSTEM EVALUATION ONLY. On production virtually every
 *     visitor would see Archivo, so shipping Museo for real needs either a
 *     webfont licence (self-hostable .woff2 - drops straight into our existing
 *     font-src 'self' CSP) or an Adobe Fonts web project (which serves from
 *     use.typekit.net and therefore costs a CSP exception).
 *
 * /!\ Chrome matches local() against the FULL NAME and the POSTSCRIPT NAME
 *     only, never the family name - a fingerprinting mitigation. That is why
 *     both spellings are listed for every weight.
 *
 * /!\ 500 and 700 are declared but are NOT installed today (only 100, 300 and
 *     the demo 900 are). They are here so they light up the moment real faces
 *     are licensed. Until then CSS font matching resolves 500 and 700 down to
 *     300, because the demo 900's family name is "FONTSPRING DEMO - Museo Sans
 *     900", NOT "Museo Sans", so it is deliberately unreachable from here.
 *     Wiring it up would be worse than omitting it: its glyph set is cut down
 *     (20K vs 64K) and accented characters render as tofu.
 */
@font-face {
	font-family: 'Museo Sans';
	src: local('Museo Sans 100'), local('MuseoSans-100');
	font-weight: 100; font-style: normal; font-display: swap;
}
@font-face {
	font-family: 'Museo Sans';
	src: local('Museo Sans 300'), local('MuseoSans-300');
	font-weight: 300; font-style: normal; font-display: swap;
}
@font-face {
	font-family: 'Museo Sans';
	src: local('Museo Sans 500'), local('MuseoSans-500');
	font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
	font-family: 'Museo Sans';
	src: local('Museo Sans 700'), local('MuseoSans-700');
	font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
	font-family: 'Museo Sans';
	src: local('Museo Sans 900'), local('MuseoSans-900');
	font-weight: 900; font-style: normal; font-display: swap;
}

@font-face {
	font-family: 'Archivo';
	src: url('/static/brand/fonts/archivo-latin-var.woff2') format('woff2');
	font-weight: 400 800;          /* one variable file covers the whole range */
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: 'IBM Plex Mono';
	src: url('/static/brand/fonts/ibmplexmono-600-latin.woff2') format('woff2');
	font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
	font-family: 'IBM Plex Mono';
	src: url('/static/brand/fonts/ibmplexmono-700-latin.woff2') format('woff2');
	font-weight: 700; font-style: normal; font-display: swap;
}

/* --- 2. Tokens. This is where nearly all the work happens. ----------------
 *
 * The compiled bundle makes 354 references to CSS custom properties -
 * --color-primary alone is used 61 times and --size-border-radius 41 - and the
 * derived shades (-text, -hover, -light, -lighter) are color-mix() off
 * --color-primary, so they follow automatically. Most apparent literal
 * `#2185d0` hits in that bundle are `var(--color-primary,#2185d0)`, i.e. the
 * hex is only a fallback. Overriding the roots is therefore far more effective
 * than chasing selectors, and survives upstream markup changes.
 *
 * ⚠ Override --color-primary DIRECTLY, never --color-pretalx. The bundle has
 *   `--color-success: var(--color-pretalx)` as well, so flipping --color-pretalx
 *   would turn success states amber.
 * ------------------------------------------------------------------------- */
:root {
	--lz-ink: #171819;
	--lz-amber: #feb300;
	--lz-amber-dk: #d99e00;
	--lz-amber-text: #7f5a00;   /* amber darkened until it passes AA on light */
	/* The navy of the event banner artwork (lz-banner-v2), sampled from the
	 * image on 2026-10-30: one flat #040e4c across the whole background. It is
	 * the hero band's blend base; the bars use --lz-band below. */
	--lz-navy: #040e4c;
	/* The menu bar and footer colour. Started as the shade the hero band
	 * renders (#131e49, the wave graphic screen-blended over --lz-navy, #111);
	 * John picked the darker #141c3a by eye on 2026-10-30 (#113). The hero
	 * keeps --lz-navy as its blend base - changing that would shift the band. */
	--lz-band: #141c3a;
	/* Museo Sans first: present only for viewers who have it installed (see the
	 * local() note above). Archivo is the SHIPPED face and the real fallback -
	 * it is self-hosted and OFL-licensed, so everyone else still gets the brand. */
	--lz-sans: 'Museo Sans', 'Archivo', 'Open Sans', OpenSans, 'Helvetica Neue', Helvetica, Arial, sans-serif;
	--lz-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

	/* The face for the uppercase, letter-spaced meta labels (event date, venue,
	 * search date). Kept SEPARATE from --lz-mono on purpose: --lz-mono is still
	 * the genuine monospace token feeding --font-family-monospace below, which
	 * <code>/<pre> rely on and which must stay monospaced.
	 *
	 * /!\ To restore the original monospace label, set this back to
	 *     var(--lz-mono) - that one line is the whole revert. */
	--lz-label: var(--lz-sans);

	--color-primary: var(--lz-amber);
	--color-header-background: var(--lz-band);
	--color-header-text: #ffffff;
	--color-danger: #d9534f;
	--color-success: #5cb85c;

	/* ⚠ --color-header-navigation is NOT on the dark header despite the name;
	 * every use of it sits on a LIGHT strip. White or amber there measures
	 * 1.09:1 and 1.65:1. Ink measures 16.31:1. Same trap as the
	 * navigation_text_color setting - see bin/apply-theme.sh. */
	--color-header-navigation: var(--lz-ink);
	--color-header-navigation-hover: var(--lz-amber-text);

	/* ⚠ Link colour. The bundle has `a { color: var(--color-primary-text) }`
	 * and `--color-primary-text: color-mix(in srgb, var(--color-primary),
	 * black 10%)`. Ten percent is enough to make stock BLUE readable on white;
	 * for amber it is not - measured #e5a100 on white = 2.23:1, below AA, and
	 * that hit every body link on the page. Amber is a LIGHT colour: it works
	 * as a background with dark text, or as text on the dark chrome, but not
	 * as text on white. #7f5a00 measures 6.24:1 on white. */
	--color-primary-text: var(--lz-amber-text);
	--color-primary-text-dark: var(--lz-amber-text);

	--font-family: var(--lz-sans);
	--font-family-title: var(--lz-sans);
	--font-family-monospace: var(--lz-mono);

	--size-border-radius: 0;
	--inner-border-radius: 0;
}

/* --- 3. The two TRUE literals - the only `#2185d0` in the bundle that is not
 *        behind a var() fallback, so the tokens above cannot reach them. ---- */
nav.navbar.navbar-inverse {
	background-color: var(--lz-band);
	border-color: transparent;
}
.startpage-sidebar-context .fa-stack .fa-circle {
	color: var(--lz-amber);
}

/* --- 4. White-on-amber. ---------------------------------------------------
 * ⚠ Upstream pairs white text with --color-primary in several places. That is
 * safe for stock pretix blue (white on #2185d0 = 3.4:1) and FAILS for our
 * amber (white on #feb300 = 1.65:1, measured 2026-10-11). Amber is a light
 * colour; it needs dark text on it, not white. These are the spots that
 * inherit that assumption on the start page. ------------------------------- */
/* ⚠ `.btn-primary` alone LOSES here, for an ordinary reason: the bundle has
 * `button, [role="button"], a.btn, ::file-selector-button, summary.btn
 * { color: white }`, and `a.btn` is (0,1,1) against `.btn-primary` (0,1,0).
 * `.btn.btn-primary` is (0,2,0) and wins. Measured: 1.8:1 -> 12.1:1. */
.btn.btn-primary,
a.btn.btn-primary,
button.btn.btn-primary,
#locale-dropdown .language-column .dropdown-item.active {
	color: var(--lz-ink);
}

/* --- 5. Typography. The bundle already routes most text through
 *        var(--font-family) / var(--font-family-title), so this is only the
 *        headings weight and the mono label treatment. --------------------- */
h1, h2, h3, h4, h5,
.startpage-hero-header,
.startpage-event-title {
	font-family: var(--lz-sans);
	/* ⚠ !important is required, and only for elements that are real h1-h6
	 * tags. Re-measured here 2026-10-11, independently of the same finding in
	 * levelzero.css: against the bundle's `h1,h2,h3,h4,h5,h6{font-weight:500}`,
	 * NO non-important author rule wins at any specificity or order -
	 * `h3{900}` last, `.startpage-event-title{900}` last, and even
	 * `html body h3.startpage-event-title{900}` all computed 500; only
	 * !important gave 900. A detached <div> with Archivo 900 computes 900, so
	 * neither the font nor the property is at fault. Note .startpage-hero-header
	 * takes 800 WITHOUT !important - it is not an h-tag, so nothing competes.
	 * The mechanism is still unexplained; do not remove without re-testing. */
	font-weight: 800 !important;
	letter-spacing: -0.01em;
}

/* The uppercase, letter-spaced label - the most recognisable cue of the
 * marketing site. Narrow selector list on purpose: applied broadly it wrecks
 * body copy.
 *
 * /!\ This was MONOSPACE (IBM Plex Mono 600) until it was moved onto --lz-label
 *     so it could follow Museo Sans. The tracking below was tuned against a
 *     monospace face, where every advance is equal; on a proportional face it
 *     may want re-tuning by eye.
 *
 * /!\ weight 600 is deliberate and matches the shipped IBM Plex Mono 600, but
 *     no Museo Sans 500/700 is installed today, so CSS font matching resolves
 *     600 down to Museo Sans 300 (Light) for viewers who do have Museo. At
 *     0.8125em, uppercase and tracked, that reads THIN. It is not a bug - it
 *     is the missing weights, and it resolves itself when they are licensed. */
.startpage-event-meta,
.startpage-event-location,
.startpage-search-date {
	font-family: var(--lz-label);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 1.6px;
	font-size: 0.8125em;
}

/* --- 6. Chrome. The hero band and the event cards. -----------------------
 * The band carries the marketing site's dotted-wave texture
 * (img/hero-background.webp, taken from levelzdev.wpenginepowered.com on
 * 2026-10-30) over ink.
 *
 * ⚠ The full-width band is NOT header.startpage-hero-header - that sits inside
 *   .container, 1570px wide at a 1900px viewport. The band is a separate
 *   layer, div.header.startpage-header, at z-index:-1 and painted by
 *   --color-header-background. elementFromPoint() never returns it (it is
 *   behind body's content box), which is why it is easy to miss. Texturing the
 *   inner header instead (the first attempt) left a textured box inside a flat
 *   black band. So: texture on the band, inner header and hero transparent. */
.startpage-header {
	background: var(--lz-navy) url('/static/brand/theme/img/hero-background.webp') center / cover no-repeat;
	/* The texture is near-black; 'screen' keeps only its lighter dots and wave,
	 * so the band reads as the banner navy with the marketing-site pattern on
	 * top, instead of the image covering the navy. */
	background-blend-mode: screen;
}
.startpage-hero-header,
.startpage-hero {
	background: transparent;
	color: #ffffff;
}

/* The footer is a dark band in the same navy as the top band, so the page is
 * framed top and bottom in one colour (#109; event pages keep the ink footer
 * from levelzero.css 6). ⚠ It has to stay dark: the badge lockup is drawn in
 * WHITE and cyan, so on the stock light footer "ZER0" and "OT CYBER SECURITY"
 * vanish. */
footer {
	background-color: var(--lz-band);
	color: #a8a5a5;
	padding: 2rem 1.25rem 1.5rem;
	margin-top: 3rem;
}
footer a,
footer .core-footer-link { color: var(--lz-amber); }
footer a:hover,
footer .core-footer-link:hover { color: #ffffff; }

/* The footer brand block - markup in the startpage_base.html override (LZ 2).
 * Same squares as levelzero.css 6b; duplicated, not shared, for the same
 * reason as the @font-face block above. */
.lz-footer-brand {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 1.5rem;
	margin-bottom: 1.5rem;
}
.lz-footer-social { display: flex; align-items: center; gap: 0.5rem; }
.lz-hashtag {
	font-family: var(--lz-sans);
	font-weight: 800;
	font-size: 2rem;
	color: var(--lz-amber);
	margin-right: 0.5rem;
}
.lz-social {
	position: relative;
	display: inline-block;
	width: 40px;
	height: 40px;
	background-color: var(--lz-amber);
}
.lz-social::before {
	content: "";
	position: absolute;
	inset: 9px;
	background-color: var(--lz-ink);
	-webkit-mask: var(--lz-icon) center / contain no-repeat;
	        mask: var(--lz-icon) center / contain no-repeat;
}
.lz-social:hover { background-color: #ffffff; }
.lz-social-linkedin  { --lz-icon: url('/static/brand/theme/img/icon-linkedin.svg'); }
.lz-social-youtube   { --lz-icon: url('/static/brand/theme/img/icon-youtube.svg'); }
.lz-social-instagram { --lz-icon: url('/static/brand/theme/img/icon-instagram.svg'); }

/* Hairlines - the marketing site's 1px #5a5a5b on every card and the header
 * (measured on levelzdev.wpenginepowered.com 2026-10-30). */
.startpage-event-card {
	border-radius: 0;
	border: 1px solid #5a5a5b;
	box-shadow: none;
}
nav.navbar.navbar-inverse { border-bottom: 1px solid #5a5a5b; }

/* --- 7. Type scale, from the marketing site's own CSS (2026-10-30). --------
 * Hero: `h1.has-x-large-font-size { font-size: clamp(2rem, 6rem, 6vw);
 * line-height: .95 }`. Their argument order is non-standard; clamp(MIN,VAL,MAX)
 * is max(MIN, min(VAL, MAX)), so it is identical to the conventional form
 * below: 96px on a wide screen, 6vw as it narrows, never under 32px.
 *
 * ⚠ The title is NOT a heading. It is the global "start page header text",
 *   rendered through |rich_text (b85c6e07), so it arrives as <p> inside
 *   header.startpage-hero-header. Sizing the header itself instead (the first
 *   attempt) left the title at 48px and inflated every em-sized child.
 *   First paragraph = the headline; any further paragraph = the marketing
 *   site's tagline treatment (20px / 500 / amber, which is legible here because
 *   this band is dark). */
.startpage-hero-header p:first-of-type {
	font-size: clamp(2rem, 6vw, 6rem);
	line-height: 0.95;
	font-weight: 800;
	letter-spacing: -0.01em;
}
.startpage-hero-header p + p {
	font-size: 1.25rem;
	font-weight: 500;
	color: var(--lz-amber);
	line-height: 1.6;
}
h2 { font-size: 2.25rem; }
h4 { font-size: 1.15rem; }
p  { line-height: 1.8; }

/* CMS pages (/page/<slug>/, e.g. "Why Attend Level Zero") render their own
 * root template, overridden as pretixcontrol/admin/pages/base.html (#120),
 * which links this file and sets body.lz-cms-page. Those pages are often
 * shorter than the window, so pin the footer to the bottom rather than leave
 * a grey strip under it. Scoped to that class: the start page's layout is
 * different and must not become a flex column. */
body.lz-cms-page { min-height: 100vh; display: flex; flex-direction: column; }
body.lz-cms-page > .container { flex: 1 0 auto; }
body.lz-cms-page > footer { flex-shrink: 0; }

/* --- 9. Sign-in pages (/login/, /common/forgot/, recover, 2FA, invite) ----
 * Their root template, eventyay_common/auth/base.html, is overridden (#122) to
 * link this file and set body.lz-auth-page. ⚠ Those pages load the CONTROL
 * bundle (auth.scss + main.scss), which has NO CSS custom properties -
 * measured 2026-10-31: --color-primary, --font-family and --size-border-radius
 * all empty there, button and links literal #2185d0. So the tokens in
 * section 2 do nothing on these pages and every rule below is explicit.
 * The nav (section 3), footer (section 6) and heading (section 5) rules
 * above already match, because they are plain selectors. */
body.lz-auth-page {
	font-family: var(--lz-sans);
	min-height: 100vh;
	display: flex;
	flex-direction: column;
}
body.lz-auth-page > .container { flex: 1 0 auto; }
body.lz-auth-page > footer { flex-shrink: 0; }

body.lz-auth-page a:not(.btn) { color: var(--lz-amber-text); }
body.lz-auth-page footer a,
body.lz-auth-page footer .core-footer-link { color: var(--lz-amber); }
body.lz-auth-page footer a:hover,
body.lz-auth-page footer .core-footer-link:hover { color: #ffffff; }
body.lz-auth-page nav.navbar a { color: #ffffff; }

body.lz-auth-page .btn.btn-primary {
	background-color: var(--lz-amber);
	border-color: var(--lz-amber);
	color: var(--lz-ink);
}
body.lz-auth-page .btn.btn-primary:hover,
body.lz-auth-page .btn.btn-primary:focus,
body.lz-auth-page .btn.btn-primary:active {
	background-color: var(--lz-amber-dk);
	border-color: var(--lz-amber-dk);
	color: var(--lz-ink);
}
body.lz-auth-page .form-control:focus {
	border-color: var(--lz-amber-dk);
	box-shadow: 0 0 0 2px rgba(254, 179, 0, 0.35);
}

/* Square corners, as on every other branded page. */
body.lz-auth-page .btn,
body.lz-auth-page .form-control,
body.lz-auth-page .input-group-addon,
body.lz-auth-page .form-signin,
body.lz-auth-page .alert { border-radius: 0; }

/* The badge is drawn in white and cyan, so it needs the navy behind it - on
 * the page's light background "ZER0" would vanish. */
body.lz-auth-page .lz-auth-logo {
	background-color: var(--lz-band);
	padding: 14px 20px;
	box-sizing: content-box;
	margin-top: 3vh;
	margin-bottom: 1.5vh;
}
