/* --- CSS Table of Contents --- */
/* 1. Self-hosted font (@font-face) */
/* 2. Root Variables (Colours & Fonts) */
/* 3. Accessibility Helpers (skip link, screen-reader status) */
/* 4. General Styles & Structure */
/* 5. Page Header & Title */
/* 6. Navigation & Header Controls */
/* 7. Form & Input Elements */
/* 8. Grid Layout for Results */
/* 9. Info Blocks (General & Scrollable) */
/* 10. Content Styling (Lists, Buttons, Raw Data) */
/* 11. Status, Error & Helper Classes */
/* 12. Security Scan Specifics */
/* 13. Static & Error Page Specifics */
/* 14. Fixed Footer */
/* 15. Dark Mode Theme */
/* 16. Media Queries for Responsiveness */
/* 17. DNS Lookup Tool */
/* 18. Protocol Grid (Expert Tools hub) */
/* 19. Protocol Tool Pages (two-column, tabs) */
/* 20. Tools Dropdown (expert.hostingdetails.eu header) */
/* 21. Comparison Table & Logo Preview (bimi.php) */
/* 22. DKIM Sweep Summary */
/* 23. Raw Record Display */
/* 24. DANE Wizard Provider Recognition */
/* 25. Reduced Motion */
/* 26. Focus Indication */
/* 27. Mail Health Check */
/* 28. DNSSEC Verdict Banner */
/* ----------------------------- */

/* File: style.css */

/* --- 1. Self-hosted font --- */
/* Replaces the Google Fonts link: fewer external requests, no dependency on
   fonts.googleapis.com/fonts.gstatic.com any more. The .woff2 files need to
   live in the /fonts/ folder on the server. */
@font-face {
	font-family: 'Lato';
	src: url('/fonts/lato-v25-latin-regular.woff2') format('woff2');
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: 'Lato';
	src: url('/fonts/lato-v25-latin-700.woff2') format('woff2');
	font-weight: 700;
	font-style: normal;
	font-display: swap;
}

/* --- 2. Root Variables --- */
:root {
	--font-family: 'Lato', sans-serif;

	--colour-background-light: #f4f6f9;
	--colour-surface-light: #ffffff;
	--colour-text-primary-light: #212529;
	/* Darkened from the original #6c757d: that shade only reached 4.14:1
	   contrast against the light page-header background, below the WCAG AA
	   minimum of 4.5:1 for normal-sized text. */
	--colour-text-secondary-light: #656d75;
	--colour-border-light: #dee2e6;
	--colour-accent-light: #8e44ad;
	--colour-accent-hover-light: #703690;
	--colour-title-bg-light: #f4eff7;

	--colour-background-dark: #121212;
	--colour-surface-dark: #1e1e1e;
	--colour-text-primary-dark: #e0e0e0;
	--colour-text-secondary-dark: #adb5bd;
	--colour-border-dark: #3a3a3a;
	--colour-accent-dark: #9b59b6;
	--colour-accent-hover-dark: #bb86fc;
	--colour-title-bg-dark: #2c2733;
	/* Lighter than --colour-accent-dark specifically for text links on the
	   dark surface: the original accent colour only reached 3.57:1 contrast
	   there, below the WCAG AA minimum of 4.5:1. Buttons/borders keep using
	   --colour-accent-dark unchanged, since those aren't held to the same
	   text-contrast rule. */
	--colour-link-dark: #b367d3;

	/* --- Status colours ---
	   Three roles, each with the same small vocabulary, so that adding a
	   page means picking a token rather than inventing a hex. Before this
	   there were 36 hard-coded colours outside :root and five different
	   greens that all meant "good".

	   solid          filled badge or dot background
	   solid-border   the border of that badge
	   text           the colour as text on the page background
	   surface        tinted background of a notice block
	   surface-border its border
	   on-surface     text on that tinted background

	   The values are unchanged except where a contrast measurement said
	   otherwise; each of those is noted where it happens.

	   Both domains carry the identical set, including tokens one of them
	   does not use yet: expert.hostingdetails.eu has no warning notice
	   and no JSON viewer at the time of writing. That is deliberate. One
	   palette across both domains is the point, so that green means the
	   same thing on either side and the day expert grows a warning block
	   it reaches for this orange rather than inventing another one. The
	   two files may differ in layout; they must not differ in what a
	   colour means. */

	--colour-ok-solid-light: #28a745;
	--colour-ok-solid-border-light: #23903c;
	/* #28a745 as text on white reaches only 3.13:1, under the WCAG AA
	   minimum of 4.5:1. This darker shade reaches 4.53:1. The brighter
	   original is fine on the dark surface (5.32:1) and is used there. */
	--colour-ok-text-light: #208838;
	--colour-ok-solid-dark: #2a7d3f;
	--colour-ok-solid-border-dark: #3ca957;
	--colour-ok-text-dark: #28a745;

	--colour-warning-solid-light: #fd7e14;
	--colour-warning-solid-border-light: #e36b07;
	/* Was #b35a08, which passes on white (4.79:1) but drops to 4.23:1 on
	   the light title background and 4.49:1 on the notice surface, both
	   under the minimum. This shade clears all three (5.9, 5.21, 5.53)
	   and happens to be the colour the JSON viewer already used for
	   booleans, so unifying costs nothing. */
	--colour-warning-text-light: #a5490b;
	--colour-warning-surface-light: #fff6ed;
	--colour-warning-solid-dark: #b3590d;
	--colour-warning-solid-border-dark: #ff9a40;
	--colour-warning-text-dark: #ff9a40;
	--colour-warning-surface-dark: #2b1d10;

	--colour-error-solid-light: #dc3545;
	--colour-error-solid-border-light: #c82333;
	--colour-error-text-light: #dc3545;
	--colour-error-surface-light: #f8d7da;
	--colour-error-surface-border-light: #f5c6cb;
	--colour-error-on-surface-light: #721c24;
	--colour-error-solid-dark: #a52834;
	--colour-error-solid-border-dark: #f15261;
	--colour-error-text-dark: #fa3c4e;
	--colour-error-surface-dark: #4d2124;
	--colour-error-surface-border-dark: #6e3539;
	--colour-error-on-surface-dark: #f5c6cb;

	/* --- Neutrals that are not borders or text ---
	   --colour-border-light already exists and is the visible border of a
	   card. These are quieter: a hairline between list rows, and the
	   background of a block of code. Four near-identical light greys
	   (#f0f0f0, #f8f9fa, #eee, #f4f4f4) sat in the stylesheets doing this
	   work; the first two are kept, the other two were the same idea
	   written twice. */
	--colour-divider-light: #f0f0f0;
	--colour-code-surface-light: #f8f9fa;
	--colour-input-surface-dark: #333333;
	--colour-muted-light: #6c757d;
	--colour-muted-dark: #9aa0a6;

	/* --- Syntax colours for the raw JSON viewer ---
	   Booleans and nulls are deliberately absent: they reuse the warning
	   and muted tokens above, since a second orange and a second grey for
	   the same job is exactly what this section exists to prevent. */
	--colour-syntax-key-light: #6f42c1;
	--colour-syntax-string-light: #0b6e4f;
	--colour-syntax-number-light: #0b5394;
	--colour-syntax-key-dark: #c39bff;
	--colour-syntax-string-dark: #7ee2b8;
	--colour-syntax-number-dark: #7cc3ff;
}

/* --- 3. Accessibility Helpers --- */
/* Two classes that only exist for people not looking at the screen, or not
   using a mouse. Placed here, directly after the variables they use, rather
   than tucked in with the components: they belong to the page as a whole. */

/* Off-screen but still read aloud. Deliberately not display:none or
   visibility:hidden, since both of those remove an element from the
   accessibility tree as well as from view, which would make a screen
   reader ignore exactly the announcements this class exists to carry.
   Used by the #a11y-status region that every page carries just inside
   <body>, which the page's own JavaScript writes short status sentences
   into ("Checking example.com", "Results ready") so that pressing a
   button is not a silent event. */
.visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* Hidden until it receives keyboard focus, then it drops into view at the
   top left. Positioned off-screen rather than hidden outright for the same
   reason as above: a skip link that cannot be focused is not a skip link.
   Its target is the id="main-content" on each page's <main> element. */
.skip-link {
	position: absolute;
	top: -100px;
	left: 8px;
	z-index: 100;
	padding: 10px 16px;
	background-color: var(--colour-accent-light);
	color: white;
	text-decoration: none;
	border-radius: 0 0 5px 5px;
	transition: top 0.15s;
}

.skip-link:focus {
	top: 0;
}

/* Not the accent colour here. White on --colour-accent-dark measures
   4.67:1, which does pass the WCAG AA minimum of 4.5:1 for normal text,
   but only just, and it reads as washed out at this size against the
   surrounding dark page. A plain dark panel with the standard light text
   measures 12.63:1 instead. The accent survives as a border, so the link
   still reads as part of this site.

   Worth stating plainly, because the name invites the wrong assumption:
   this link is for anyone navigating by keyboard, not only for people
   using a screen reader. Plenty of them are looking straight at it. */
body.dark-mode .skip-link {
	background-color: var(--colour-surface-dark);
	color: var(--colour-text-primary-dark);
	border: 2px solid var(--colour-accent-dark);
	border-top: none;
}

/* --- 4. General Styles & Structure --- */
body {
	font-family: var(--font-family);
	margin: 0;
	padding: 15px;
	background-color: var(--colour-background-light);
	color: var(--colour-text-primary-light);
	font-size: 0.9em;
	line-height: 1.4;
	padding-bottom: 70px;
}

.container {
	max-width: 1400px;
	margin: 0 auto;
}

/* General link colour: nothing set this anywhere before, so links fell
   back to the browser default blue. Fine (if unbranded) against a light
   background, but unreadable against the dark-mode background further
   down, see that section for the actual fix this was written for. More
   specific selectors (.nav-link, .site-footer a, .button) already exist
   and win on specificity, so this only affects plain prose links (e.g.
   static-page-content, info-block text). */
a {
	color: var(--colour-accent-light);
}
a:hover {
	color: var(--colour-accent-hover-light);
}

/* --- 5. Page Header & Title --- */
.page-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: 15px;
	background-color: var(--colour-title-bg-light);
	padding: 0 10px 0 20px;
	border-radius: 8px;
	border-bottom: 3px solid var(--colour-accent-light);
}

.page-header h1 a {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	text-decoration: none;
	color: inherit;
}

/* Groups the site title with the cross-domain link, so that link sits
   on the left next to the branding instead of drifting to the right
   among the controls. It points at the other domain, not at a tool on
   this one, which is a different kind of link and now reads as one. */
.header-brand {
	display: flex;
	align-items: center;
	gap: 12px;
}

/* SVG has 1365x1365 baked into its width/height attributes. Without
   this rule it renders at that size and blows out the header. Height
   is set in em so it scales with the h1's own font-size rather than
   a fixed pixel value. */
.site-logo {
	height: 1.4em;
	width: auto;
	flex-shrink: 0;
}

h1 {
	font-size: 1.6em;
	margin: 0;
	padding: 15px 0;
	color: var(--colour-text-primary-light);
	background-color: transparent;
	border-bottom: none;
	text-align: left;
}

.info-block h2 {
	/* This is the card-title style previously on a bare "h3" selector.
	   Rescoped to .info-block and moved from h3 to h2 because these cards
	   (on index.php and security-scan.php) were the page's only headings
	   below <h1>, since a heading level going straight from <h1> to <h3>,
	   skipping <h2> entirely, which an accessibility audit correctly
	   flagged. There was never a real <h2> on either page to nest under,
	   so these ARE the page's top-level content sections and h2 is the
	   semantically correct level. See main.js / scan.js for where these
	   are generated. */
	font-size: 1em;
	margin: 0;
	padding: 10px 15px;
	background-color: var(--colour-title-bg-light);
	border-bottom: 1px solid var(--colour-border-light);
	color: var(--colour-text-secondary-light);
	font-weight: 600;
}

h4 {
	margin-top: 15px;
	margin-bottom: 5px;
	font-size: 0.9em;
	text-transform: uppercase;
	color: var(--colour-text-secondary-light);
}

/* --- 6. Navigation & Header Controls --- */
.header-controls {
	display: flex;
	align-items: center;
	gap: 10px;
	flex-wrap: wrap;
}

.nav-link {
	font-size: 0.9em;
	font-weight: bold;
	color: var(--colour-text-secondary-light);
	text-decoration: none;
	padding: 8px 12px;
	border-radius: 5px;
	transition: background-color 0.2s, color 0.2s;
}

.nav-link:hover {
	background-color: rgba(0,0,0,0.05);
	color: var(--colour-text-primary-light);
}

.nav-link.button-style {
	background-color: var(--colour-title-bg-light);
	border: 1px solid var(--colour-border-light);
}

.nav-link.button-style:hover {
	border-color: var(--colour-text-secondary-light);
}

/* --- 7. Form & Input Elements --- */
/* flex-wrap lets forms with more than one labelled field (e.g.
   dkim.php's domain + optional selector) wrap onto a new line in the
   narrower right-hand column of .tool-layout, rather than squeezing
   every field down to its min-width or overflowing sideways.
   Single-field forms (index.php, dns-lookup.php) are unaffected, they
   never have enough content to wrap in the first place. */
form {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	margin-bottom: 15px;
	align-items: center;
}

form input[type="text"] {
	flex-grow: 1;
	padding: 8px;
	border: 1px solid var(--colour-border-light);
	border-radius: 5px;
	font-size: 1em;
	background-color: var(--colour-surface-light);
	color: var(--colour-text-primary-light);
	height: 22px;
	color-scheme: light;
	min-width: 50px;
}

form button[type="submit"] {
	padding: 9px 15px;
	border: none;
	background-color: var(--colour-accent-light);
	color: white;
	border-radius: 5px;
	cursor: pointer;
	font-size: 1em;
	font-weight: bold;
	transition: background-color 0.2s;
}

form button[type="submit"]:hover {
	background-color: var(--colour-accent-hover-light);
}

/* --- 8. Grid Layout for Results --- */
.hidden { display: none; }

#results-grid, #scan-results-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	grid-auto-rows: minmax(180px, auto);
	gap: 12px;
}

#results-grid {
	grid-template-areas: "whois whois ip" "dns ssl dnssec";
}

#whois-rdap-block { grid-area: whois; }
#ip-block { grid-area: ip; }
#dns-block { grid-area: dns; }
#ssl-block { grid-area: ssl; }
#dnssec-block { grid-area: dnssec; }

/* Fixed positions for the security-scan cards, keyed by id rather than
   DOM order. When a mail-port scan omits the Headers card (see scan.js),
   this keeps SSL and Email in their usual spots instead of shifting left
   to fill the gap. A card's position stays the card's position, whether
   or not its neighbours are present. */
#scan-results-grid #header-scan-block { grid-column: 1; }
#scan-results-grid #ssl-scan-block { grid-column: 2; }
#scan-results-grid #email-scan-block { grid-column: 3; }

/* When only an IP address was looked up (goal 3): a single wide block
   instead of the fixed 5-block layout. Toggled via main.js (the "ip-only"
   class). */
#results-grid.ip-only {
	grid-template-columns: 1fr;
	grid-template-areas: "ip";
}

/* --- 9. Info Blocks (General & Scrollable) --- */
.info-block {
	border: 1px solid var(--colour-border-light);
	border-radius: 6px;
	background-color: var(--colour-surface-light);
	box-shadow: 0 1px 3px rgba(0,0,0,0.05);
	display: flex;
	flex-direction: column;
	overflow: hidden;
}

.info-block .content {
	padding: 12px 15px;
	overflow-y: auto;
	flex-grow: 1;
	display: flex;
	flex-direction: column;
}

.content-container {
	flex-grow: 1;
}

/* --- 10. Content Styling --- */
.summary-list {
	list-style-type: none;
	padding: 0;
	margin: 0;
	font-size: 0.9em;
}

.summary-list li {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 5px 0;
	border-bottom: 1px solid var(--colour-divider-light);
}

.summary-list li:last-child {
	border-bottom: none;
}

.summary-list li strong {
	color: var(--colour-text-secondary-light);
	margin-right: 15px;
	flex-shrink: 0;
}

.summary-list li span {
	text-align: right;
	word-break: break-all;
}

/* Replaces inline style="" attributes previously used in main.js (DNSSEC
   display): required because the Content-Security-Policy no longer allows
   inline style attributes (see the updated .htaccess). */
.key-detail-row {
	flex-direction: column;
	align-items: flex-start;
}

.key-detail-value {
	text-align: left;
	word-break: break-all;
	margin-top: 5px;
}

.key-detail-spacer {
	padding: 5px 0;
	border-bottom: none;
}

/* Replaces the remaining inline style="margin-top:15px" attributes on <h4>
   sub-headings (DNS/SSL/DNSSEC output) and style="text-align:center" on the
   "no issues found" message (security scan output). Both were still
   present in main.js/scan.js and got blocked by the Content-Security-Policy
   the same way the DNSSEC key details were earlier. */
.subsection-heading {
	margin-top: 15px;
}

.status-ok-centered {
	text-align: center;
}

.details-buttons {
	margin-top: 15px;
	padding-top: 10px;
	border-top: 1px solid var(--colour-divider-light);
}

.details-buttons button, .details-toggle {
	padding: 5px 10px;
	font-size: 0.8em;
	cursor: pointer;
	border: 1px solid var(--colour-border-light);
	background-color: var(--colour-title-bg-light);
	border-radius: 4px;
	color: var(--colour-text-primary-light);
}

#raw-data-display pre {
	max-height: 200px;
	overflow-y: auto;
	background-color: var(--colour-code-surface-light);
	padding: 10px;
	border-radius: 4px;
	white-space: pre-wrap;
	word-break: break-word;
	font-size: 0.8em;
	line-height: 1.6;
}

.details-toggle {
	display: block;
	margin-top: 10px;
}

.details-content.hidden {
	display: none;
}

/* --- 11. Status, Error & Helper Classes --- */
.status-ok {
	color: var(--colour-ok-text-light);
	font-weight: bold;
}

.status-error {
	color: var(--colour-error-text-light);
	font-weight: bold;
}

.status-warning {
	color: var(--colour-warning-text-light);
	font-weight: bold;
}

.error {
	color: var(--colour-error-on-surface-light);
	background-color: var(--colour-error-surface-light);
	border: 1px solid var(--colour-error-surface-border-light);
	padding: 15px;
	border-radius: 5px;
}

.summary-list-divider {
	border-top: 1px solid var(--colour-divider-light);
	margin: 10px 0;
}

.flag-icon {
	height: 12px;
	width: 16px;
	vertical-align: middle;
	margin-left: 5px;
	border: 1px solid var(--colour-divider-light);
}

.list-pre {
	margin: 0;
	padding: 0;
	white-space: pre-wrap;
	word-break: break-all;
}

#darkModeToggle {
	height: 38px;
	width: 38px;
	padding: 6px;
	background-color: transparent;
	border: 1px solid var(--colour-border-light);
	border-radius: 5px;
	cursor: pointer;
	display: flex;
	align-items: center;
	justify-content: center;
	transition: background-color 0.2s, border-color 0.2s;
}

#darkModeToggle:hover {
	background-color: rgba(0,0,0,0.05);
}

#darkModeToggle svg {
	width: 20px;
	height: 20px;
	stroke: var(--colour-border-light);
	stroke-width: 2;
	fill: none;
	transition: stroke 0.2s;
}

#darkModeToggle:hover svg {
	stroke: var(--colour-text-secondary-light);
}

/* --- 12. Security Scan Specifics --- */
.score-container {
	text-align: center;
	margin-bottom: 20px;
}

.score-circle {
	width: 100px;
	height: 100px;
	border-radius: 50%;
	color: white;
	font-size: 2.5em;
	font-weight: bold;
	display: flex;
	justify-content: center;
	align-items: center;
	margin: 0 auto 10px auto;
	border: 5px solid;
}

.score-Aplus, .score-A {
	background-color: var(--colour-ok-solid-light);
	border-color: var(--colour-ok-solid-border-light);
}

.score-B {
	background-color: var(--colour-warning-solid-light);
	border-color: var(--colour-warning-solid-border-light);
}

.score-C {
	background-color: var(--colour-error-solid-light);
	border-color: var(--colour-error-solid-border-light);
}

.findings-title {
	margin-top: 0;
}

.findings-list {
	list-style-type: none;
	padding: 0;
	margin: 0;
	font-size: 0.9em;
}

.findings-list li {
	padding: 5px 0 5px 20px;
	position: relative;
	border-bottom: 1px solid var(--colour-divider-light);
}

.findings-list li:last-child {
	border-bottom: none;
}

/* Was a 10px coloured circle, which meant the verdict was carried by
   colour and by nothing else. Around one in twelve men cannot reliably
   separate the green, orange and red used here, and a screen reader read
   an empty span, so the same information was missing for two different
   groups at once.

   It is now a character as well as a colour, and the span carries a
   hidden word (see STATUS_LABELS in the page's own script). The colour
   stays exactly as it was: reinforcement now, rather than the whole
   message.

   The class is still called .status-dot even though it no longer draws
   one. Renaming it would mean touching eleven script files for a
   cosmetic reason, and a file missed in that pass would silently lose
   its indicator altogether. */
.status-dot {
	display: inline-block;
	position: absolute;
	left: 0;
	top: 4px;
	width: 14px;
	font-size: 0.95em;
	font-weight: 700;
	line-height: 1.4;
	text-align: center;
}

.status-dot.status-good::before { content: "\2713"; }
.status-dot.status-ok::before   { content: "!"; }
.status-dot.status-bad::before  { content: "\2715"; }
.status-dot.status-info::before { content: "i"; }

/* The text variants of the tokens, not the solid ones: these are
   characters on the card background now rather than filled shapes, so
   they fall under the contrast rule for text. */
.status-dot.status-good { color: var(--colour-ok-text-light); }
.status-dot.status-ok { color: var(--colour-warning-text-light); }
.status-dot.status-bad { color: var(--colour-error-text-light); }
.status-dot.status-info { color: var(--colour-muted-light); }

body.dark-mode .status-dot.status-good { color: var(--colour-ok-text-dark); }
body.dark-mode .status-dot.status-ok { color: var(--colour-warning-text-dark); }
body.dark-mode .status-dot.status-bad { color: var(--colour-error-text-dark); }
body.dark-mode .status-dot.status-info { color: var(--colour-muted-dark); }

/* --- 13. Static & Error Page Specifics --- */
.page-intro, .error-page-content, .static-page-content {
	text-align: center;
	padding: 20px;
	background-color: var(--colour-surface-light);
	border: 1px solid var(--colour-border-light);
	border-radius: 8px;
	margin: 0 auto 30px auto;
	max-width: 800px;
}

.page-intro h2, .error-page-content h1, .static-page-content h2 {
	font-size: 2em;
	background: none;
	border: none;
	padding: 0;
	margin-top: 10px;
	text-align: center;
}

.page-intro p {
	max-width: 700px;
	margin: 10px auto;
}

.static-page-content h2 {
	margin-bottom: 20px;
	border-bottom: 1px solid var(--colour-border-light);
	padding-bottom: 10px;
}

.error-page-content .error-code {
	font-size: 5em;
	font-weight: bold;
	color: var(--colour-accent-light);
	margin: 0;
	opacity: 0.6;
}

.error-dig-output {
	text-align: left;
	display: inline-block;
	max-width: 500px;
}

.error-page-content p, .static-page-content p {
	color: var(--colour-text-secondary-light);
	max-width: 650px;
	margin: 15px auto;
	text-align: left;
}

.error-page-content .button, .static-page-content .button {
	display: inline-block;
	padding: 10px 25px;
	background-color: var(--colour-accent-light);
	color: white;
	border-radius: 5px;
	text-decoration: none;
	font-weight: bold;
	margin-top: 20px;
	transition: background-color 0.2s;
}

.error-page-content .button:hover, .static-page-content .button:hover {
	background-color: var(--colour-accent-hover-light);
}

.static-page-content {
	text-align: left;
}

.static-page-content h3 {
	background: none;
	border: none;
	padding: 0;
	margin-top: 25px;
}

/* --- External Link Container --- */
.external-link-container {
	margin-top: auto;
	padding-top: 15px;
	border-top: 1px solid var(--colour-divider-light);
	text-align: center;
}

.external-link-container p {
	font-size: 0.85em;
	font-style: italic;
	color: var(--colour-text-secondary-light);
	margin: 0 0 10px 0;
}

.external-link-container .button {
	display: inline-block;
	padding: 8px 15px;
	font-size: 0.9em;
	background-color: var(--colour-accent-light);
	color: white;
	text-decoration: none;
	border-radius: 5px;
	transition: background-color 0.2s;
	white-space: nowrap;
	margin: 0 5px;
}

.external-link-container .button:hover {
	background-color: var(--colour-accent-hover-light);
}
/* --- 14. Fixed Footer --- */
.site-footer {
	position: fixed;
	left: 0;
	bottom: 0;
	width: 100%;
	background-color: var(--colour-surface-light);
	border-top: 1px solid var(--colour-border-light);
	padding: 10px 20px;
	text-align: center;
	font-size: 0.8em;
	z-index: 100;
	box-shadow: 0 -2px 5px rgba(0,0,0,0.05);
}

.site-footer a {
	color: var(--colour-accent-light);
	text-decoration: none;
}

.site-footer a:hover {
	text-decoration: underline;
}

/* --- 15. Dark Mode Theme --- */
body.dark-mode {
	background-color: var(--colour-background-dark);
	color: var(--colour-text-primary-dark);
}

/* This is the actual fix for the unreadable dark-blue-on-dark-background
   links reported on how-it-works.php (and, by the same gap, privacy.php
   and terms.php): general "a" only had a LIGHT-mode colour set above, so
   in dark mode every plain prose link fell through to the raw browser
   default blue, which fails contrast against the dark background.
   --colour-link-dark already existed and was already WCAG-AA-checked
   (see its definition in the root variables), it just wasn't applied
   this broadly yet, only to .site-footer/.nav-link. */
body.dark-mode a {
	color: var(--colour-link-dark);
}
body.dark-mode a:hover {
	color: var(--colour-accent-hover-dark);
}

body.dark-mode .page-header {
	background-color: var(--colour-title-bg-dark);
	border-bottom-color: var(--colour-accent-dark);
}

body.dark-mode h1,
body.dark-mode h3 {
	color: var(--colour-text-primary-dark);
}

body.dark-mode .info-block {
	background-color: var(--colour-surface-dark);
	border-color: var(--colour-border-dark);
}

body.dark-mode .info-block h2 {
	background-color: var(--colour-title-bg-dark);
	border-bottom-color: var(--colour-border-dark);
	color: var(--colour-text-secondary-dark);
}

/* Matches the light-mode .static-page-content h3 override above (which
   removes the boxed look for these plain-prose sub-headings). Without
   this, dark mode had no equivalent override, so these headings picked
   up the boxed background/border from the generic "h3" dark-mode rule
   above instead, which was never the intent (visible as an unwanted bar
   behind headings like "1. The homepage..." on how-it-works.php). */
body.dark-mode .static-page-content h3 {
	background: none;
	border: none;
}

body.dark-mode .summary-list li,
body.dark-mode .details-buttons,
body.dark-mode .external-link-container,
body.dark-mode .summary-list-divider,
body.dark-mode .findings-list li {
	border-color: var(--colour-border-dark);
}

body.dark-mode .summary-list li strong {
	color: var(--colour-text-secondary-dark);
}

body.dark-mode #raw-data-display pre,
body.dark-mode .details-buttons button,
body.dark-mode .details-toggle {
	background-color: var(--colour-title-bg-dark);
	border-color: var(--colour-border-dark);
	color: var(--colour-text-primary-dark);
}

body.dark-mode .error {
	background-color: var(--colour-error-surface-dark);
	border-color: var(--colour-error-surface-border-dark);
	color: var(--colour-error-on-surface-dark);
}

/* The light-mode .status-ok/.status-error colours above were tuned for
   light backgrounds. Both need a dark-mode override to keep passing WCAG AA
   (4.5:1) against the dark surface colour. */
body.dark-mode .status-ok {
	color: var(--colour-ok-text-dark);
}

body.dark-mode .status-error {
	color: var(--colour-error-text-dark);
}

body.dark-mode .status-warning {
	color: var(--colour-warning-text-dark);
}

body.dark-mode form input[type="text"] {
	background-color: var(--colour-input-surface-dark);
	border-color: var(--colour-border-dark);
	color: var(--colour-text-primary-dark);
	color-scheme: dark;
}

body.dark-mode form button[type="submit"] {
	background-color: var(--colour-accent-dark);
}

/* Buttons darken on hover in dark mode, rather than lightening.
   --colour-accent-hover-dark (#bb86fc) is the hover colour for link
   TEXT on a dark background, where a lighter purple is right. Used as a
   button background it collides with the rule that sets it: any .button
   that is an <a> gets its text turned that same #bb86fc by
   "body.dark-mode a:hover", so the label vanished into the background
   at the moment the pointer arrived. Every button on this subdomain
   that is a link has behaved that way; the submit buttons never did,
   only because they are <button> elements and that rule does not reach
   them.
   Darkening instead keeps the behaviour identical to the light theme,
   reuses a colour that already exists rather than adding one, and takes
   white text from 2.65:1 to 5.87:1. The explicit colour is there to
   override the a:hover rule, which is more specific than the button's
   own. */
body.dark-mode form button[type="submit"]:hover {
	background-color: var(--colour-accent-light);
	color: white;
}

body.dark-mode .site-footer {
	background-color: var(--colour-surface-dark);
	border-top-color: var(--colour-border-dark);
}

body.dark-mode .site-footer a,
body.dark-mode .nav-link {
	color: var(--colour-link-dark);
}

body.dark-mode .nav-link:hover {
	background-color: rgba(255,255,255,0.05);
	color: var(--colour-text-primary-dark);
}

body.dark-mode .nav-link.button-style {
    background-color: var(--colour-title-bg-dark);
    border-color: var(--colour-border-dark);
}

body.dark-mode .nav-link.button-style:hover {
    border-color: var(--colour-text-secondary-dark);
}

body.dark-mode #darkModeToggle {
	border-color: var(--colour-border-dark);
}

body.dark-mode #darkModeToggle:hover {
	background-color: rgba(255,255,255,0.05);
}

body.dark-mode #darkModeToggle svg {
	stroke: var(--colour-border-dark);
}

body.dark-mode #darkModeToggle:hover svg {
	stroke: var(--colour-text-secondary-dark);
}

body.dark-mode .page-intro,
body.dark-mode .error-page-content,
body.dark-mode .static-page-content {
	background-color: var(--colour-surface-dark);
	border-color: var(--colour-border-dark);
}

body.dark-mode .error-page-content .error-code {
	color: var(--colour-accent-dark);
}

body.dark-mode .error-page-content p,
body.dark-mode .static-page-content p,
body.dark-mode .external-link-container p {
	color: var(--colour-text-secondary-dark);
}

body.dark-mode .error-page-content .button,
body.dark-mode .static-page-content .button,
body.dark-mode .external-link-container .button {
	background-color: var(--colour-accent-dark);
}

body.dark-mode .error-page-content .button:hover,
body.dark-mode .static-page-content .button:hover,
body.dark-mode .external-link-container .button:hover {
	background-color: var(--colour-accent-light);
	color: white;
}

body.dark-mode .static-page-content h2 {
	border-bottom-color: var(--colour-border-dark);
}

body.dark-mode .score-Aplus,
body.dark-mode .score-A {
	background-color: var(--colour-ok-solid-dark);
	border-color: var(--colour-ok-solid-border-dark);
}

body.dark-mode .score-B {
	background-color: var(--colour-warning-solid-dark);
	border-color: var(--colour-warning-solid-border-dark);
}

body.dark-mode .score-C {
	background-color: var(--colour-error-solid-dark);
	border-color: var(--colour-error-solid-border-dark);
}

/* --- 16. Media Queries for Responsiveness --- */
@media (max-width: 1200px) {
	.container {
		max-width: 95%;
	}
}

@media (max-width: 992px) {
	#results-grid, #scan-results-grid {
		grid-template-columns: repeat(2, 1fr);
	}
	#results-grid {
		grid-template-areas: "whois whois" "ip dns" "ssl dnssec";
	}
	/* Re-map the fixed security-scan positions to the 2-column layout:
	   Headers/SSL share row 1, Email wraps to row 2 col 1. Still keyed by
	   id, still leaves an empty gap rather than shifting when Headers is
	   omitted. */
	#scan-results-grid #header-scan-block { grid-column: 1; }
	#scan-results-grid #ssl-scan-block { grid-column: 2; }
	#scan-results-grid #email-scan-block { grid-column: 1; }
}

@media (max-width: 768px) {
	body {
		padding: 10px;
		padding-bottom: 70px;
	}
	.page-header {
		flex-direction: column;
		align-items: stretch;
		text-align: center;
		padding: 0 10px;
	}
	.page-header h1 {
		text-align: center;
	}
	.header-brand {
		flex-direction: column;
		align-items: center;
		gap: 6px;
	}
	.header-controls {
		justify-content: center;
		padding: 10px 0;
	}
	#darkModeToggle {
		position: absolute;
		top: 15px;
		right: 10px;
	}
	#results-grid, #scan-results-grid {
		grid-template-columns: 1fr;
	}
	#results-grid {
		grid-template-areas: "whois" "ip" "dns" "ssl" "dnssec";
	}
	/* Single column: the fixed grid-column positions above would otherwise
	   force extra (empty) implicit columns here, breaking the stack, so
	   every security-scan card goes back to column 1 and just stacks in
	   DOM order, same as before this feature existed. */
	#scan-results-grid #header-scan-block,
	#scan-results-grid #ssl-scan-block,
	#scan-results-grid #email-scan-block {
		grid-column: 1;
	}
	form {
		flex-direction: column;
		align-items: stretch;
	}
	form input[type="text"] {
		margin-bottom: 10px;
	}
}

/* --- 17. DNS Lookup Tool --- */
.dns-lookup-form {
	flex-direction: column;
	align-items: stretch;
	gap: 15px;
}

/* Two-thirds / one-third split: query fields on the left, nameserver
   selection on the right. */
.dns-lookup-grid {
	display: grid;
	grid-template-columns: 2fr 1fr;
	gap: 20px;
	align-items: start;
}

.hostname-type-row {
	display: flex;
	align-items: flex-start;
	gap: 10px;
}

.hostname-type-row textarea {
	flex-grow: 1;
	padding: 8px;
	border: 1px solid var(--colour-border-light);
	border-radius: 5px;
	font-size: 0.9em;
	font-family: 'Courier New', Courier, monospace;
	background-color: var(--colour-surface-light);
	color: var(--colour-text-primary-light);
	resize: vertical;
	min-height: 90px;
}

.hostname-type-row select {
	flex-shrink: 0;
	padding: 8px;
	border: 1px solid var(--colour-border-light);
	border-radius: 5px;
	font-size: 1em;
	background-color: var(--colour-surface-light);
	color: var(--colour-text-primary-light);
}

.dns-lookup-servers {
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.server-options-row {
	display: flex;
	justify-content: space-between;
	align-items: flex-start;
	gap: 12px;
}

.checkbox-group {
	display: flex;
	flex-direction: column;
	gap: 6px;
}

.option-group {
	display: flex;
	flex-direction: column;
	gap: 6px;
	align-items: flex-end;
	flex-shrink: 0;
}

.checkbox-option {
	display: flex;
	align-items: center;
	gap: 6px;
	font-weight: normal;
	cursor: pointer;
}

.checkbox-option input[type="checkbox"] {
	width: auto;
	flex-grow: 0;
	cursor: pointer;
	accent-color: var(--colour-accent-light);
}

.checkbox-option-right {
	justify-content: flex-end;
}

.checkbox-option input[type="checkbox"]:disabled {
	cursor: not-allowed;
}

.checkbox-option:has(input:disabled) {
	color: var(--colour-text-secondary-light);
	cursor: not-allowed;
}

.custom-servers-row input[type="text"]:disabled {
	opacity: 0.6;
	cursor: not-allowed;
}

.custom-servers-row {
	display: flex;
	flex-direction: column;
	gap: 4px;
}

.custom-servers-row label {
	font-size: 0.85em;
	color: var(--colour-text-secondary-light);
}

.custom-servers-row input[type="text"] {
	padding: 8px;
	border: 1px solid var(--colour-border-light);
	border-radius: 5px;
	font-size: 0.9em;
	background-color: var(--colour-surface-light);
	color: var(--colour-text-primary-light);
}

.field-hint {
	font-size: 0.8em;
	color: var(--colour-text-secondary-light);
}

.field-hint.field-hint-error {
	color: var(--colour-error-text-light);
}

.dns-output-block {
	margin-top: 15px;
}

.dig-output {
	font-family: 'Courier New', Courier, monospace;
	font-size: 0.85em;
	line-height: 1.6;
	white-space: pre-wrap;
	word-break: break-all;
	background-color: var(--colour-code-surface-light);
	padding: 15px;
	border-radius: 4px;
	margin: 0;
}

/* Colour coding within the dig-style output. */
.dig-meta {
	color: var(--colour-text-secondary-light);
}

.dig-section {
	color: var(--colour-accent-light);
	font-weight: bold;
}

.dig-name {
	color: var(--colour-text-primary-light);
}

.dig-ttl {
	color: var(--colour-text-secondary-light);
}

.dig-type {
	color: var(--colour-accent-light);
	font-weight: bold;
}

.dig-value {
	color: var(--colour-text-primary-light);
}

/* Separator between the results of different nameservers. */
.dig-block-divider {
	border: none;
	border-top: 1px dashed var(--colour-border-light);
	margin: 15px 0;
}

body.dark-mode .hostname-type-row textarea,
body.dark-mode .hostname-type-row select,
body.dark-mode .custom-servers-row input[type="text"] {
	background-color: var(--colour-input-surface-dark);
	border-color: var(--colour-border-dark);
	color: var(--colour-text-primary-dark);
}

body.dark-mode .custom-servers-row label,
body.dark-mode .field-hint {
	color: var(--colour-text-secondary-dark);
}

body.dark-mode .checkbox-option:has(input:disabled) {
	color: var(--colour-text-secondary-dark);
}

body.dark-mode .dig-output {
	background-color: var(--colour-title-bg-dark);
	color: var(--colour-text-primary-dark);
}

body.dark-mode .dig-meta,
body.dark-mode .dig-ttl {
	color: var(--colour-text-secondary-dark);
}

body.dark-mode .dig-section,
body.dark-mode .dig-type {
	color: var(--colour-link-dark);
}

body.dark-mode .dig-name,
body.dark-mode .dig-value {
	color: var(--colour-text-primary-dark);
}

body.dark-mode .dig-block-divider {
	border-top-color: var(--colour-border-dark);
}

@media (max-width: 768px) {
	.dns-lookup-grid {
		grid-template-columns: 1fr;
	}
}

/* --- 18. Protocol Grid (Expert Tools hub) --- */
/* Only used on expert.hostingdetails.eu's index.php. Reuses the same
   card language as .info-block, arranged as a fixed 3-column grid, one
   card per protocol, each with a short explanation and a link through
   to that protocol's own page. Cards are grouped under a heading
   (Mail - (almost) mandatory / Mail - nice to have / DNS / Overall
   security). h3 is the group title, so cards themselves step down to
   h4 to keep the heading hierarchy honest.

   max-width matches .page-intro's 800px (plus a little, since cards
   want a touch more room) so the whole hub reads as one centred column
   of content, not an intro box floating above a grid pinned to the
   container's own edges. */
.protocol-group {
	max-width: 1020px;
	margin: 0 auto 24px auto;
}

.protocol-group-title {
	margin: 0 0 10px;
	font-size: 1em;
	text-transform: uppercase;
	letter-spacing: 0.03em;
	color: var(--colour-text-secondary-light);
}

body.dark-mode .protocol-group-title {
	color: var(--colour-text-secondary-dark);
}

.protocol-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 20px;
	margin-bottom: 0;
}

/* Modifier for a group with only one card (e.g. the future "Overall
   security" / Headers group), placing it in the centre column of the
   same 3-column grid, rather than pinned to the left. */
.protocol-grid--single .protocol-card {
	grid-column: 2;
}

@media (max-width: 720px) {
	.protocol-grid {
		grid-template-columns: 1fr;
	}
	.protocol-grid--single .protocol-card {
		grid-column: 1;
	}
}

/* For two single-card groups that should sit apart with a third
   card's worth of space between them, rather than side by side with
   only the ordinary gap (e.g. "Start here" and "Mail infrastructure").
   Reuses the same 3-column grid as an ordinary three-card row, so the
   two cards line up with where the first and third card of any other
   row would sit; the middle column is simply never filled. Works
   identically whether the children are .protocol-card elements or a
   matching pair of .protocol-group-title headings placed above them,
   since the rule targets any direct child by position, not by type. */
.protocol-grid--spaced > *:first-child {
	grid-column: 1;
}

.protocol-grid--spaced > *:last-child {
	grid-column: 3;
}

@media (max-width: 720px) {
	.protocol-grid--spaced > *:first-child,
	.protocol-grid--spaced > *:last-child {
		grid-column: 1;
	}
}

.protocol-card {
	border: 1px solid var(--colour-border-light);
	border-radius: 6px;
	background-color: var(--colour-surface-light);
	box-shadow: 0 1px 3px rgba(0,0,0,0.05);
	padding: 15px 18px;
	display: flex;
	flex-direction: column;
}

.protocol-card h4 {
	margin: 0 0 8px;
	font-size: 1.1em;
	color: var(--colour-text-primary-light);
}

.protocol-card p {
	color: var(--colour-text-secondary-light);
	flex-grow: 1;
	margin: 0 0 15px;
}

.protocol-card .button {
	display: inline-block;
	align-self: center;
	padding: 8px 18px;
	background-color: var(--colour-accent-light);
	color: white;
	border-radius: 5px;
	text-decoration: none;
	font-weight: bold;
	transition: background-color 0.2s;
}

.protocol-card .button:hover {
	background-color: var(--colour-accent-hover-light);
}

body.dark-mode .protocol-card {
	background-color: var(--colour-surface-dark);
	border-color: var(--colour-border-dark);
}

body.dark-mode .protocol-card h4 {
	color: var(--colour-text-primary-dark);
}

body.dark-mode .protocol-card p {
	color: var(--colour-text-secondary-dark);
}

body.dark-mode .protocol-card .button {
	background-color: var(--colour-accent-dark);
}

body.dark-mode .protocol-card .button:hover {
	background-color: var(--colour-accent-light);
	color: white;
}
/* --- 19. Protocol Tool Pages (two-column, tabs, fixed-viewport on desktop) --- */
/* Used by individual protocol pages (spf.php and the ones that follow
   it). Goal: fit on one screen at desktop/FullHD sizes without
   page-level scrolling. A panel that grows too tall for the available
   height scrolls internally instead, reusing .info-block's existing
   overflow-y: auto .content rather than a new mechanism. Reverts to
   normal document flow below the 768px breakpoint already used
   elsewhere in this file, where scrolling is expected and fine. */
body.tool-page {
	box-sizing: border-box;
	height: 100vh;
	display: flex;
	flex-direction: column;
	overflow: hidden;
}

body.tool-page .container {
	flex: 1;
	display: flex;
	flex-direction: column;
	min-height: 0;
}

body.tool-page main {
	flex: 1;
	min-height: 0;
	display: flex;
}

.tool-layout {
	display: grid;
	grid-template-columns: minmax(260px, 1fr) minmax(340px, 1.4fr);
	gap: 16px;
	flex: 1;
	min-height: 0;
	align-items: stretch;
}

.tool-tabs {
	display: flex;
	gap: 4px;
	margin-bottom: 12px;
}

.tool-tab-btn {
	flex: 1;
	padding: 8px 0;
	border: 1px solid var(--colour-border-light);
	border-radius: 5px;
	background-color: transparent;
	color: var(--colour-text-secondary-light);
	font-weight: bold;
	cursor: pointer;
	transition: background-color 0.2s, color 0.2s, border-color 0.2s;
}

.tool-tab-btn.active {
	background-color: var(--colour-accent-light);
	color: white;
	border-color: var(--colour-accent-light);
}

.tool-tab-panel.hidden {
	display: none;
}

body.dark-mode .tool-tab-btn {
	border-color: var(--colour-border-dark);
	color: var(--colour-text-secondary-dark);
}

body.dark-mode .tool-tab-btn.active {
	background-color: var(--colour-accent-dark);
	color: white;
	border-color: var(--colour-accent-dark);
}

@media (max-width: 900px) {
	body.tool-page {
		height: auto;
		overflow: visible;
	}
	body.tool-page main {
		display: block;
	}
	.tool-layout {
		display: block;
	}
	.tool-explanation, .tool-panel {
		margin-bottom: 12px;
	}
}

/* Wizard fields (spf.php and friends). Standalone inputs/selects that
   live outside a <form>, so the existing "form input[type=text]" etc.
   rules in section 6 don't reach them, so these are the equivalents. */
.wizard-field {
	margin-bottom: 12px;
}

.wizard-field label {
	display: block;
	margin-bottom: 4px;
}

.wizard-field input[type="text"],
.wizard-field textarea,
.wizard-field select {
	width: 100%;
	padding: 6px;
	border: 1px solid var(--colour-border-light);
	border-radius: 5px;
	background-color: var(--colour-surface-light);
	color: var(--colour-text-primary-light);
	box-sizing: border-box;
	font-family: var(--font-family);
}

#wizardCopyButton {
	padding: 8px 15px;
	border: 1px solid var(--colour-border-light);
	background-color: var(--colour-title-bg-light);
	color: var(--colour-text-primary-light);
	border-radius: 5px;
	cursor: pointer;
	font-weight: bold;
	margin-top: 8px;
}

body.dark-mode .wizard-field input[type="text"],
body.dark-mode .wizard-field textarea,
body.dark-mode .wizard-field select {
	border-color: var(--colour-border-dark);
	background-color: var(--colour-surface-dark);
	color: var(--colour-text-primary-dark);
}

body.dark-mode .checkbox-option input[type="checkbox"] {
	accent-color: var(--colour-accent-dark);
}

body.dark-mode #wizardCopyButton {
	border-color: var(--colour-border-dark);
	background-color: var(--colour-title-bg-dark);
	color: var(--colour-text-primary-dark);
}

/* --- 20. Tools Dropdown (expert.hostingdetails.eu header) --- */
/* Replaces a growing row of individual nav-links with a single button
   that opens a dropdown list, whereas the main domain's header has three
   links and a row works fine there, but this subdomain's protocol list
   is expected to grow to nine or ten, which would either wrap onto
   several lines or force the header past a sensible height. */
.tools-menu {
	position: relative;
}

.tools-menu-icon {
	width: 16px;
	height: 16px;
	vertical-align: -3px;
	margin-right: 4px;
}

.tools-menu-list {
	position: absolute;
	top: calc(100% + 6px);
	right: 0;
	min-width: 160px;
	margin: 0;
	padding: 6px;
	list-style: none;
	background-color: var(--colour-surface-light);
	border: 1px solid var(--colour-border-light);
	border-radius: 6px;
	box-shadow: 0 4px 12px rgba(0,0,0,0.15);
	z-index: 50;
}

.tools-menu-list.hidden {
	display: none;
}

.tools-menu-list li {
	margin: 0;
}

.tools-menu-list a {
	display: block;
	padding: 8px 10px;
	border-radius: 4px;
	color: var(--colour-text-primary-light);
	text-decoration: none;
	font-weight: bold;
	font-size: 0.9em;
}

.tools-menu-list a:hover {
	background-color: var(--colour-title-bg-light);
	color: var(--colour-text-primary-light);
}

body.dark-mode .tools-menu-list {
	background-color: var(--colour-surface-dark);
	border-color: var(--colour-border-dark);
}

body.dark-mode .tools-menu-list a {
	color: var(--colour-text-primary-dark);
}

body.dark-mode .tools-menu-list a:hover {
	background-color: var(--colour-title-bg-dark);
	color: var(--colour-text-primary-dark);
}

/* --- 21. Comparison Table & Logo Preview (bimi.php) --- */
/* No table existed anywhere else on this subdomain yet, so this is
   the first one, used by bimi.php's certificate/provider overview.
   The logo preview below it renders the data: URI api/bimi-check.php
   returns. See that file's comment on why it's data: and not a
   direct <img src> to the checked domain's own logo URL. */
.bimi-provider-table {
	width: 100%;
	border-collapse: collapse;
	margin: 10px 0 15px;
	font-size: 0.9em;
}

.bimi-provider-table th,
.bimi-provider-table td {
	border: 1px solid var(--colour-border-light);
	padding: 6px 10px;
	text-align: left;
}

.bimi-provider-table th {
	background-color: var(--colour-title-bg-light);
	font-weight: bold;
}

body.dark-mode .bimi-provider-table th,
body.dark-mode .bimi-provider-table td {
	border-color: var(--colour-border-dark);
}

body.dark-mode .bimi-provider-table th {
	background-color: var(--colour-title-bg-dark);
}

.bimi-logo-preview {
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 20px;
	margin-bottom: 12px;
	border: 1px solid var(--colour-border-light);
	border-radius: 6px;
	/* Deliberately always light, in both themes, because a BIMI logo has no
	   guaranteed background of its own (many, like this one, are a
	   plain dark wordmark with no fill behind it), and mail clients
	   that actually display these logos always do so against a light
	   background. Matching that here means every logo stays legible,
	   regardless of this site's own theme. */
	background-color: var(--colour-divider-light);
}

.bimi-logo-preview img {
	max-width: 120px;
	max-height: 120px;
}

/* --- 22. DKIM Sweep Summary --- */
/* Sits above the findings list only when a sweep (no selector entered)
   turns up more than one match: a plain count plus the "this isn't
   exhaustive" disclaimer, so five near-identical "DKIM record found"
   lines aren't the first thing read. */
.check-summary {
	padding: 10px 12px;
	margin-bottom: 12px;
	border: 1px solid var(--colour-border-light);
	border-radius: 6px;
	background-color: var(--colour-title-bg-light);
	font-size: 0.9em;
}

body.dark-mode .check-summary {
	border-color: var(--colour-border-dark);
	background-color: var(--colour-title-bg-dark);
}

/* --- 23. Raw Record Display --- */
/* Sits above the findings list on any check that parses a specific DNS
   record, showing the actual value(s) retrieved before any
   interpretation of them. Same monospace/code-surface treatment as
   .dig-output, deliberately, since both are "here is exactly what came
   back" boxes. A record with sub_items (currently only DKIM's SPF
   include: breakdown) gets a small indented list underneath its own
   block rather than a second heading. */
.raw-record-label {
	margin: 0 0 4px;
	font-size: 0.85em;
	font-weight: bold;
	color: var(--colour-text-secondary-light);
}

body.dark-mode .raw-record-label {
	color: var(--colour-text-secondary-dark);
}

.raw-record-block {
	margin-bottom: 12px;
}

.raw-record-block pre {
	font-family: 'Courier New', Courier, monospace;
	font-size: 0.85em;
	line-height: 1.6;
	white-space: pre-wrap;
	word-break: break-all;
	background-color: var(--colour-code-surface-light);
	padding: 10px 12px;
	border-radius: 4px;
	margin: 0;
}

body.dark-mode .raw-record-block pre {
	background-color: var(--colour-code-surface-dark);
}

/* Picks out the header name on each line of headers.php's raw block,
   same treatment as .dig-type on the DNS Lookup Tool: this page's own
   renderRawRecordsHtml() wraps it in this span, every other page's
   copy of that function doesn't, since a "name: value" line is
   specific to HTTP headers, not DNS record text in general. */
.header-name {
	color: var(--colour-accent-light);
	font-weight: bold;
}

body.dark-mode .header-name {
	color: var(--colour-link-dark);
}

.raw-record-block details pre {
	margin-top: 8px;
}

.raw-record-sub-list {
	margin: 6px 0 0;
	padding-left: 20px;
	font-size: 0.85em;
	color: var(--colour-text-secondary-light);
}

body.dark-mode .raw-record-sub-list {
	color: var(--colour-text-secondary-dark);
}

/* --- 24. DANE Wizard Provider Recognition --- */
/* Shown above the manual "pick a certificate" controls when a served
   intermediate matches a known CA from lib/data/ca-intermediates.json -
   offers pinning that CA's full current set (all active + backup
   intermediates) in one click, instead of only today's single served
   certificate. */
.wizard-provider-match {
	padding: 10px 12px;
	margin-bottom: 14px;
	border: 1px solid var(--colour-accent-light);
	border-radius: 6px;
	background-color: rgba(139, 45, 186, 0.08);
	font-size: 0.9em;
}

.wizard-provider-match p {
	margin: 0 0 8px;
}

#wizardPinRotationButton {
	padding: 8px 15px;
	border: none;
	background-color: var(--colour-accent-light);
	color: white;
	border-radius: 5px;
	cursor: pointer;
	font-size: 1em;
	font-weight: bold;
	transition: background-color 0.2s;
}

#wizardPinRotationButton:hover {
	background-color: var(--colour-accent-hover-light);
}

body.dark-mode #wizardPinRotationButton {
	background-color: var(--colour-accent-dark);
}

body.dark-mode #wizardPinRotationButton:hover {
	background-color: var(--colour-accent-light);
	color: white;
}

body.dark-mode .wizard-provider-match {
	border-color: var(--colour-accent-dark);
	background-color: rgba(155, 89, 182, 0.12);
}

.page-intro-disclaimer {
	font-size: 0.85em;
	color: var(--colour-text-secondary-light);
	margin-top: 8px;
}

body.dark-mode .page-intro-disclaimer {
	color: var(--colour-text-secondary-dark);
}

/* The page the visitor is already on. Marked rather than removed from
   the list, so the menu always shows the same set of tools. Colour and
   style both carry the distinction, never colour alone. */
.tools-menu-list a[aria-current="page"] {
	color: var(--colour-accent-light);
	font-style: italic;
}

body.dark-mode .tools-menu-list a[aria-current="page"] {
	color: var(--colour-accent-dark);
}

/* --- 25. Reduced Motion --- */
/* Honours the system-level "reduce motion" preference. What is left in
   this stylesheet is a handful of 0.2s colour fades on hover, which
   nobody notices and which stop a button's colour from snapping; the one
   transition that was actually visible, the 0.3s cross-fade on the theme
   switch, was removed instead of kept.

   That removal was a decision, not an oversight. It only ever applied to
   the page background, so cards, headings and borders switched instantly
   while the background drifted. Half a transition reads worse than
   either whole one, and this site is not a place where anything needs to
   glide.

   This block stays anyway, because some people are genuinely made unwell
   by movement and honouring their setting costs almost nothing. */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		transition-duration: 0.01ms !important;
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		scroll-behavior: auto !important;
	}
}

/* --- 26. Focus Indication --- */
/* Until now only the skip link had a focus rule and everything else, all
   the links, buttons, inputs, selects and the Tools menu, leaned on
   whatever the browser draws. That is not automatically wrong, but it is
   never checked either: with a mouse you never see it.

   Two things went wrong when it was measured. The submit buttons are
   themselves the accent colour, so an accent ring drawn on them would
   have a contrast of 1.0, which is to say invisible. And on the dark
   theme's input field the accent reaches only 2.71:1, under the 3.0
   minimum for non-text contrast.

   outline-offset fixes both at once by moving the ring off the element
   and onto the background behind it. There the accent measures 5.87:1 on
   a light card and 3.57:1 on a dark one, and a purple button surrounded
   by a purple ring on a dark card is perfectly readable because the ring
   is not on the button.

   :focus-visible rather than :focus on purpose: the browser only matches
   it when focus arrives by keyboard, so clicking a button with a mouse
   does not leave a ring behind. */
:focus-visible {
	outline: 2px solid var(--colour-accent-light);
	outline-offset: 2px;
	/* Some elements, notably the dark-mode toggle and the JSON tree's
	   summary rows, have a border radius; without this the ring is a
	   square around a rounded shape. */
	border-radius: 3px;
}

body.dark-mode :focus-visible {
	outline-color: var(--colour-accent-dark);
}

/* The skip link is the exception: it sits hard against the top edge, so
   a ring offset outwards would be clipped. Its own rule in section 3
   already brings it into view on focus, which is indication enough. */
.skip-link:focus-visible {
	outline-offset: -4px;
	border-radius: 0 0 5px 5px;
}

/* --- 27. Mail Health Check --- */
/* Two elements the protocol pages do not have: a verdict above the
   findings, and a list of next steps below them. */

/* The one-line verdict. Deliberately not scored and not coloured by
   severity: a number would suggest SPF and DMARC can be weighed against
   each other, and a domain with perfect SPF and no DMARC is not
   "seventy-five percent secure", it is unprotected in a specific way
   that the findings underneath spell out. */
.mail-health-headline {
	margin: 0 0 15px 0;
	font-size: 1.1em;
	line-height: 1.4;
	padding-bottom: 10px;
	border-bottom: 1px solid var(--colour-border-light);
}

body.dark-mode .mail-health-headline {
	border-bottom-color: var(--colour-border-dark);
}

/* The next steps repeat what the findings already said, on purpose:
   somebody scanning for "what do I do now" should find it in one place,
   and hearing the same thing twice in a different shape is how it
   sticks. The button leads, the reason follows it in smaller type. */
.next-steps-list {
	list-style: none;
	padding: 0;
	margin: 0;
}

.next-steps-list li {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 10px;
	padding: 10px 0;
	border-bottom: 1px solid var(--colour-divider-light);
}

.next-steps-list li:last-child {
	border-bottom: none;
}

body.dark-mode .next-steps-list li {
	border-bottom-color: var(--colour-border-dark);
}

/* There is no bare .button rule in this stylesheet: every one of them is
   scoped to a parent (.protocol-card, .static-page-content and so on).
   So this needs its own, matching .protocol-card's exactly rather than
   inventing a third look for the same thing. */
.next-steps-list .button {
	display: inline-block;
	flex-shrink: 0;
	/* A fixed width rather than one per label. Four buttons of four
	   different widths stacked under each other break the left edge of
	   the list and leave the reasons beside them starting in four
	   different places; one width lines up both columns. 280px is a
	   whole number of the 5px unit and fits the longest label these
	   steps produce, which is an SPF record for a subdomain. Longer
	   labels wrap inside the button rather than widening it. */
	width: 280px;
	text-align: center;
	padding: 8px 18px;
	background-color: var(--colour-accent-light);
	color: white;
	border-radius: 5px;
	text-decoration: none;
	font-weight: bold;
	transition: background-color 0.2s;
}

.next-steps-list .button:hover {
	background-color: var(--colour-accent-hover-light);
}

body.dark-mode .next-steps-list .button {
	background-color: var(--colour-accent-dark);
}

body.dark-mode .next-steps-list .button:hover {
	background-color: var(--colour-accent-light);
	color: white;
}

.next-step-reason {
	flex: 1 1 200px;
	font-size: 0.9em;
	color: var(--colour-text-secondary-light);
	line-height: 1.4;
}

body.dark-mode .next-step-reason {
	color: var(--colour-text-secondary-dark);
}

/* Below this the two columns no longer fit side by side, so the reason
   drops under its button and a fixed width would only leave the button
   stranded in a narrow strip. */
@media (max-width: 720px) {
	.next-steps-list .button {
		width: 100%;
	}
}

/* --- 28. DNSSEC Verdict Banner --- */
/* The one-line conclusion dnssec.js puts above everything else once a
   check returns a verdict (SECURE/BOGUS/UNVERIFIABLE/NOT SIGNED/
   INCOMPLETE) - added 13 September once the check started doing real
   cryptographic chain validation rather than only presence checks,
   since a genuine pass/fail result deserves to be read first, with
   the full evidence chain (raw records, then every individual finding)
   still available below it for anyone who wants to see why. Reuses
   the same four status colours every status-dot on this site already
   uses, so a verdict never introduces a fifth colour meaning. */
.dnssec-verdict {
	display: flex;
	align-items: flex-start;
	gap: 12px;
	padding: 14px 16px;
	margin-bottom: 16px;
	border-radius: 6px;
	border: 1px solid var(--colour-border-light);
	background-color: var(--colour-surface-light);
}

.dnssec-verdict-icon {
	font-size: 1.4em;
	font-weight: 700;
	line-height: 1.2;
}

.dnssec-verdict strong {
	display: block;
	font-size: 1.1em;
	letter-spacing: 0.03em;
}

.dnssec-verdict p {
	margin: 4px 0 0;
}

.dnssec-verdict.verdict-secure .dnssec-verdict-icon,
.dnssec-verdict.verdict-secure strong {
	color: var(--colour-ok-text-light);
}

.dnssec-verdict.verdict-bogus .dnssec-verdict-icon,
.dnssec-verdict.verdict-bogus strong,
.dnssec-verdict.verdict-not-signed .dnssec-verdict-icon,
.dnssec-verdict.verdict-not-signed strong {
	color: var(--colour-error-text-light);
}

.dnssec-verdict.verdict-unverifiable .dnssec-verdict-icon,
.dnssec-verdict.verdict-unverifiable strong,
.dnssec-verdict.verdict-incomplete .dnssec-verdict-icon,
.dnssec-verdict.verdict-incomplete strong {
	color: var(--colour-warning-text-light);
}

body.dark-mode .dnssec-verdict {
	background-color: var(--colour-surface-dark);
	border-color: var(--colour-border-dark);
}

body.dark-mode .dnssec-verdict.verdict-secure .dnssec-verdict-icon,
body.dark-mode .dnssec-verdict.verdict-secure strong {
	color: var(--colour-ok-text-dark);
}

body.dark-mode .dnssec-verdict.verdict-bogus .dnssec-verdict-icon,
body.dark-mode .dnssec-verdict.verdict-bogus strong,
body.dark-mode .dnssec-verdict.verdict-not-signed .dnssec-verdict-icon,
body.dark-mode .dnssec-verdict.verdict-not-signed strong {
	color: var(--colour-error-text-dark);
}

body.dark-mode .dnssec-verdict.verdict-unverifiable .dnssec-verdict-icon,
body.dark-mode .dnssec-verdict.verdict-unverifiable strong,
body.dark-mode .dnssec-verdict.verdict-incomplete .dnssec-verdict-icon,
body.dark-mode .dnssec-verdict.verdict-incomplete strong {
	color: var(--colour-warning-text-dark);
}