/*
Theme Name: TTS Cyber
Theme URI: https://ttscyber.com
Author: TTS Cyber
Description: Custom theme for ttscyber.com — managed IT and cybersecurity in Columbus, Ohio. Built for page speed and AI answer-engine visibility. No page builder, one stylesheet, schema generated from the same data that renders the visible copy.
Version: 0.1.0
Requires at least: 6.5
Tested up to: 7.0
Requires PHP: 8.1
License: GPL v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: ttscyber
*/

/* ==========================================================================
   This is the ONLY stylesheet the site loads.

   The build it replaces inlines ~144 KB of CSS into every document — 74% of the
   homepage, uncacheable, re-downloaded on every pageview, because that is how
   the page builder emits block styles. One file the browser caches once is the
   entire reason this theme exists.

   Colours below are the site's real, measured brand colours. Every value used
   on text carries its computed WCAG contrast ratio in a comment. Where a brand
   colour fails at body size, a text-safe variant sits beside it with hue and
   saturation preserved and only lightness moved. Use the brand token for fills,
   rules and gradients; switch to the -text variant the moment it colours a
   glyph. That is not a preference — five of the six brand colours fail WCAG
   1.4.3 on white, and the live site ships those failures today.

     1.  Fonts            9.  Hero
     2.  Tokens          10.  Cards and grids
     3.  Reset and base  11.  Sections
     4.  Layout          12.  Blog
     5.  Typography      13.  Forms
     6.  Links, buttons  14.  Utilities
     7.  Header          15.  Responsive
     8.  Footer          16.  Motion, focus, print
   ========================================================================== */

/* 1. Fonts =================================================================
   Self-hosted WOFF2. The live site declares Poppins in four @font-face blocks
   totalling 652 KB of TTF, under family names ("Poppins Medium", "Poppins
   Bold") that no CSS rule ever requests — so it downloads all of it and then
   renders the whole page in the OS UI stack anyway.

   Three weights, latin subset, ~15 KB each. font-display:swap so text paints
   immediately and is never invisible while the font loads.

   Run `bash tools/fetch-fonts.sh` to populate assets/fonts/. If the files are
   absent the stack falls through to system-ui, and the admin says so rather
   than letting it ship silently.
   ========================================================================== */

@font-face {
	font-family: "Poppins";
	src: url("assets/fonts/poppins-400.woff2") format("woff2");
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: "Poppins";
	src: url("assets/fonts/poppins-600.woff2") format("woff2");
	font-weight: 600;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: "Poppins";
	src: url("assets/fonts/poppins-700.woff2") format("woff2");
	font-weight: 700;
	font-style: normal;
	font-display: swap;
}

/* 2. Tokens ================================================================ */

:root {
	/* --- Navy ramp -------------------------------------------------------
	   The live site ships six navies with no system behind them, because the
	   page builder let every row pick its own. These are the four that appear
	   on 11 of 11 pages, dark to light. --navy is the header bar and the only
	   surface the white logo is designed for. */
	--navy:         #072446;
	--navy-2:       #002646;
	--navy-3:       #133665;
	--navy-4:       #053865;
	--navy-band:    #1a466b;

	/* --- Neutrals --------------------------------------------------------- */
	--ink:          #12263f;   /* body text — 15.28:1 on white, AAA. The live
	                              value is #000001, effectively pure black at
	                              20.98:1; softened because pure black on white
	                              halates at body size. */
	--body:         #444444;   /* 9.74:1 on white — AAA */
	--muted:        #565d66;   /* 6.66:1 on white — AA, not AAA */
	--muted-text:   #4d545c;   /* 7.67:1 on white — muted copy that must hit AAA */
	--line:         #e3e7ee;
	--line-navy:    rgba(207, 207, 207, 0.27);
	--paper:        #f8f7ff;
	--paper-2:      #f2f7ff;
	--white:        #ffffff;

	/* --- Brand -----------------------------------------------------------
	   --red is THE brand colour: 426 uses across 11 of 11 pages. */
	--red:          #d43028;
	--gold:         #ffc900;
	--orange:       #ffa121;
	--sky:          #6a9afa;
	--tint-red:     #ffd5d5;

	/* --- Text-safe variants ----------------------------------------------
	   --red clears AA at body size on white unaided, which is unusual for a
	   brand red and worth keeping. The others are nowhere close and must never
	   colour a glyph directly. */
	--red-text:     #d43028;   /* 4.94:1 on white — AA */
	--red-text-aaa: #a92620;   /* 7.03:1 on white — AAA */
	--red-on-navy:  #ffa79f;   /* 8.36:1 on --navy, 5.29:1 on --navy-band — both
	                              certified, because this token is applied to
	                              BOTH surfaces (.tts-section--band and .tts-cta
	                              sit on --navy-band, everything else on
	                              --navy/-2/-3/-4). An earlier value here
	                              (#e0625c) was only ever checked against
	                              --navy — 4.4977:1 there, which rounds to
	                              4.50:1 and reads as a pass at 2-decimal
	                              precision despite failing the 4.5:1 AA floor;
	                              shown to 4 decimals here specifically because
	                              rounding hid the failure once. It was 2.85:1
	                              on --navy-band, which is how the "Service
	                              Areas" eyebrow and any --band link shipped
	                              failing WCAG 1.4.3. The brand red itself is
	                              3.15:1 on --navy and 1.99:1 on --navy-band,
	                              so any red glyph, link or ghost-button label
	                              on a dark surface uses this instead — never
	                              the raw --red token. */
	--gold-on-navy: #ffc900;   /* 10.08:1 on --navy — the brand gold needs no
	                              adjustment on dark */
	--gold-text:    #8f7000;   /* 4.68:1 on white. Brand gold is 1.54:1 on
	                              white, the worst offender on the site.
	                              Previous value #927300 measured 4.49:1 —
	                              below the 4.5:1 AA floor its comment
	                              claimed, close enough (0.01) that no visual
	                              review caught it. */
	--orange-text:  #ad6400;   /* 4.57:1 on white (brand value 2.02:1).
	                              Previous value #af6500 measured 4.48:1,
	                              same class of near-miss as --gold-text. */
	--sky-text:     #2a6af0;   /* 4.75:1 on white (brand value 2.76:1).
	                              Previous value #296ef8 measured 4.49:1,
	                              same class of near-miss as --gold-text. */

	/* --- Type ------------------------------------------------------------- */
	--font-head:    "Poppins", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
	--font-body:    "Poppins", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

	/* --- Layout ----------------------------------------------------------- */
	--container:     1200px;
	--measure:       68ch;      /* readable line length for prose */
	--gutter:        1.25rem;
	--radius:        10px;
	--radius-sm:     4px;
	--radius-lg:     24px;
	--shadow:        0 15px 25px 0 rgba(0, 0, 0, 0.10);
	--shadow-sm:     0 10px 20px rgba(44, 62, 80, 0.05);
	--header-h:      76px;
	--space-section: 80px;

	/* --- Scale ------------------------------------------------------------
	   clamp() rather than breakpoint steps, so type scales continuously and
	   there is no viewport width at which it is visibly wrong. */
	--step--1: clamp(0.83rem, 0.80rem + 0.15vw, 0.92rem);
	--step-0:  clamp(1rem, 0.96rem + 0.20vw, 1.09rem);
	--step-1:  clamp(1.20rem, 1.12rem + 0.40vw, 1.45rem);
	--step-2:  clamp(1.44rem, 1.30rem + 0.70vw, 1.94rem);
	--step-3:  clamp(1.73rem, 1.50rem + 1.15vw, 2.58rem);
	--step-4:  clamp(2.07rem, 1.71rem + 1.80vw, 3.44rem);
}

/* 3. Reset and base ======================================================== */

*,
*::before,
*::after {
	box-sizing: border-box;
}

html {
	-webkit-text-size-adjust: 100%;
	scroll-behavior: smooth;
	/* Anchored headings otherwise land underneath the sticky header. */
	scroll-padding-top: calc(var(--header-h) + 1rem);
}

body {
	margin: 0;
	font-family: var(--font-body);
	font-size: var(--step-0);
	line-height: 1.65;
	color: var(--body);
	background: var(--white);
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
}

img,
picture,
svg,
video {
	max-width: 100%;
	height: auto;
	display: block;
}

svg {
	fill: currentColor;
}

/* Every content image should carry real alt text. functions.php tags the ones
   that do not; this makes them impossible to miss while logged in. The live
   site has an empty alt on every content image, including the logo. */
.logged-in img[data-tts-alt-missing] {
	outline: 3px dashed var(--red);
	outline-offset: 2px;
}

ul,
ol {
	padding-left: 1.25em;
}

hr {
	border: 0;
	border-top: 1px solid var(--line);
	margin: 2.5rem 0;
}

table {
	width: 100%;
	border-collapse: collapse;
	font-size: var(--step--1);
}

th,
td {
	text-align: left;
	padding: 0.6rem 0.8rem;
	border-bottom: 1px solid var(--line);
}

th {
	font-family: var(--font-head);
	font-weight: 600;
	color: var(--ink);
}

/* Wide content scrolls inside its own box; the page body never scrolls
   sideways. A horizontally scrolling document is the most common mobile
   layout failure there is. */
.tts-scroll-x {
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
}

code,
kbd,
samp {
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
	font-size: 0.9em;
	background: var(--paper);
	padding: 0.15em 0.4em;
	border-radius: var(--radius-sm);
}

/* 4. Layout ================================================================ */

.tts-container {
	width: 100%;
	max-width: var(--container);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

.tts-container--narrow {
	max-width: 820px;
}

.tts-section {
	padding-block: var(--space-section);
}

.tts-section--tight {
	padding-block: calc(var(--space-section) * 0.6);
}

.tts-section--paper { background: var(--paper); }

.tts-section--navy {
	background: var(--navy);
	color: #e8eef7;      /* 13.34:1 on --navy */
}

.tts-section--band {
	background: var(--navy-band);
	color: #e8eef7;      /* 8.44:1 on --navy-band */
}

.tts-section__head {
	max-width: var(--measure);
	margin-bottom: 2.5rem;
}

.tts-section__head--center {
	margin-inline: auto;
	text-align: center;
}

.tts-eyebrow {
	font-family: var(--font-head);
	font-size: var(--step--1);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--red-text);
	margin: 0 0 0.6rem;
}

.tts-section--navy .tts-eyebrow,
.tts-section--band .tts-eyebrow,
.tts-hero .tts-eyebrow {
	color: var(--red-on-navy);
}

.tts-lede {
	font-size: var(--step-1);
	line-height: 1.55;
	color: var(--muted-text);
	max-width: var(--measure);
}

.tts-section--navy .tts-lede,
.tts-section--band .tts-lede {
	color: #cfdaea;
}

/* Prose — the wrapper for imported blog content and any long-form copy.
   The 93 posts are plain semantic HTML (p, h2, h3, ul, ol, strong, em, a) with
   no wrappers and no inline styles, so styling them is exactly a matter of
   styling those elements and nothing else. */
.tts-prose {
	max-width: var(--measure);
}

.tts-prose > * + * { margin-top: 1.15em; }
.tts-prose h2 { margin-top: 2.2em; }
.tts-prose h3 { margin-top: 1.8em; }

.tts-prose ul,
.tts-prose ol { padding-left: 1.4em; }

.tts-prose li + li { margin-top: 0.4em; }

.tts-prose img {
	border-radius: var(--radius);
	margin-block: 2rem;
}

.tts-prose blockquote {
	margin: 2rem 0;
	padding: 0.25rem 0 0.25rem 1.5rem;
	border-left: 3px solid var(--red);
	color: var(--ink);
	font-size: var(--step-1);
}

/* 5. Typography ============================================================ */

h1, h2, h3, h4, h5, h6 {
	font-family: var(--font-head);
	color: var(--ink);
	line-height: 1.2;
	margin: 0 0 0.6em;
	font-weight: 700;
	text-wrap: balance;
}

.tts-section--navy :is(h1, h2, h3, h4),
.tts-section--band :is(h1, h2, h3, h4),
.tts-hero :is(h1, h2, h3),
.tts-pagehead :is(h1, h2) {
	color: var(--white);
}

h1 { font-size: var(--step-4); letter-spacing: -0.02em; }
h2 { font-size: var(--step-3); letter-spacing: -0.01em; }
h3 { font-size: var(--step-2); }
h4 { font-size: var(--step-1); font-weight: 600; }
h5, h6 { font-size: var(--step-0); font-weight: 600; }

p {
	margin: 0 0 1.15em;
	text-wrap: pretty;
}

p:last-child { margin-bottom: 0; }

strong {
	font-weight: 600;
	color: var(--ink);
}

.tts-section--navy strong,
.tts-section--band strong { color: var(--white); }

/* 6. Links and buttons ===================================================== */

a {
	color: var(--red-text-aaa);
	text-decoration-thickness: 1px;
	text-underline-offset: 0.18em;
}

a:hover { color: var(--red); }

/* Every surface a plain (unclassed) link can appear on with a dark
   background. Widened to include .tts-header, .tts-pagehead and .tts-cta —
   omitted originally, which is how the header's own nav/phone links needed
   their own bespoke colours to avoid the base `a` rule's ~2:1 contrast on
   navy. A future link with no special class (a category description, a CTA
   passed through parts/cta.php's `text` argument) now inherits a safe colour
   on any of these instead of silently failing WCAG 1.4.3. */
.tts-section--navy a,
.tts-section--band a,
.tts-hero a,
.tts-header a,
.tts-pagehead a,
.tts-cta a { color: var(--red-on-navy); }

.tts-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	font-family: var(--font-head);
	font-size: var(--step-0);
	font-weight: 600;
	line-height: 1.2;
	padding: 0.85rem 1.6rem;
	border-radius: var(--radius-sm);
	border: 2px solid transparent;
	text-decoration: none;
	cursor: pointer;
	transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.tts-btn--primary {
	background: var(--red);
	color: var(--white);   /* 4.94:1 — AA */
	border-color: var(--red);
}

.tts-btn--primary:hover {
	background: var(--red-text-aaa);
	border-color: var(--red-text-aaa);
	color: var(--white);
}

/* A dark-surface link rule (above) and a button's own text colour are equal
   specificity as single classes, and the compound selector — .tts-hero a,
   .tts-section--navy a, etc. — is a class+tag pair that outscores
   .tts-btn--primary's single class. That let the section rule win on every
   .tts-btn--primary rendered on a dark surface: header.php's own "Get in
   Touch" button and the homepage hero button both took --red-on-navy text
   on a --red fill, which measured 1.43:1 — a red button with a barely-visible
   red label. The container+button-class compound below restores button text
   colour with a matching specificity so it always wins on these surfaces,
   regardless of what a future link-colour rule does. */
.tts-hero .tts-btn--primary,
.tts-header .tts-btn--primary,
.tts-pagehead .tts-btn--primary,
.tts-cta .tts-btn--primary,
.tts-section--navy .tts-btn--primary,
.tts-section--band .tts-btn--primary {
	color: var(--white);
}

.tts-btn--secondary {
	background: transparent;
	color: var(--ink);
	border-color: var(--ink);
}

.tts-btn--secondary:hover {
	background: var(--ink);
	color: var(--white);
}

/* On dark surfaces the outline and label go white, not brand red: red on
   --navy is 3.15:1 and fails at button-label size. */
.tts-section--navy .tts-btn--secondary,
.tts-section--band .tts-btn--secondary,
.tts-hero .tts-btn--secondary,
.tts-cta .tts-btn--secondary {
	color: var(--white);
	border-color: rgba(255, 255, 255, 0.65);
}

.tts-section--navy .tts-btn--secondary:hover,
.tts-section--band .tts-btn--secondary:hover,
.tts-hero .tts-btn--secondary:hover,
.tts-cta .tts-btn--secondary:hover {
	background: var(--white);
	color: var(--navy);
	border-color: var(--white);
}

.tts-btn-row {
	display: flex;
	flex-wrap: wrap;
	gap: 0.85rem;
	margin-top: 1.75rem;
}

/* 7. Header ================================================================ */

.tts-skip {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 999;
	padding: 0.75rem 1.25rem;
	background: var(--white);
	color: var(--ink);
	font-weight: 600;
}

.tts-skip:focus { left: 0; }

.tts-header {
	position: sticky;
	top: 0;
	z-index: 100;
	background: var(--navy);
	color: var(--white);
}

.tts-header__bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1.5rem;
	min-height: var(--header-h);
}

/* The icon is a square badge mark (assets/img/tts-logo.webp), not a wide
   lockup — it renders beside the text wordmark rather than replacing it, so
   this link is a row rather than a single swapped-in child. */
.tts-header__logo {
	display: flex;
	align-items: center;
	gap: 0.55rem;
}

.tts-header__logo img {
	height: 32px;
	width: auto;
}

/* Text wordmark. Always visible now — the icon is decorative and pairs with
   it — and this is also the sole masthead when no logo asset exists at all. */
.tts-header__logo-text,
.tts-footer__logo-text {
	font-family: var(--font-head);
	font-weight: 700;
	font-size: var(--step-1);
	letter-spacing: -0.01em;
	color: var(--white);
	white-space: nowrap;
}

.tts-nav ul {
	display: flex;
	align-items: center;
	gap: 1.6rem;
	list-style: none;
	margin: 0;
	padding: 0;
}

.tts-nav a {
	font-family: var(--font-head);
	font-size: var(--step--1);
	font-weight: 500;
	color: #dce5f2;      /* 12.25:1 on --navy */
	text-decoration: none;
	padding-block: 0.5rem;
	border-bottom: 2px solid transparent;
	white-space: nowrap;
}

.tts-nav a:hover,
.tts-nav .current-menu-item > a,
.tts-nav a[aria-current="page"] {
	color: var(--white);
	border-bottom-color: var(--red-on-navy);
}

.tts-header__actions {
	display: flex;
	align-items: center;
	gap: 1rem;
}

.tts-header__phone {
	font-family: var(--font-head);
	font-weight: 600;
	font-size: var(--step--1);
	color: var(--white);
	text-decoration: none;
	white-space: nowrap;
}

.tts-nav-toggle {
	display: none;
	align-items: center;
	gap: 0.5rem;
	background: none;
	border: 1px solid rgba(255, 255, 255, 0.35);
	border-radius: var(--radius-sm);
	color: var(--white);
	font-family: var(--font-head);
	font-size: var(--step--1);
	font-weight: 600;
	padding: 0.5rem 0.8rem;
	cursor: pointer;
}

/* 8. Footer ================================================================ */

.tts-footer {
	background: var(--navy-4);
	color: #cfdaea;      /* 8.45:1 on --navy-4 */
	padding-top: 4rem;
	font-size: var(--step--1);
}

.tts-footer__grid {
	display: grid;
	grid-template-columns: 1.4fr 1fr 1fr 1.2fr;
	gap: 2.5rem;
	padding-bottom: 3rem;
}

.tts-footer :is(h2, h3) {
	font-size: var(--step-0);
	color: var(--white);
	margin-bottom: 1rem;
}

.tts-footer ul {
	list-style: none;
	margin: 0;
	padding: 0;
}

.tts-footer li + li { margin-top: 0.55rem; }

.tts-footer a {
	color: #cfdaea;
	text-decoration: none;
}

.tts-footer a:hover {
	color: var(--white);
	text-decoration: underline;
}

/* Same pairing as .tts-header__logo — icon beside the text wordmark, not
   instead of it. The bottom margin moves here from the img rule since the
   whole row, not just the icon, needs to clear the tagline below it. */
.tts-footer__logo {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	margin-bottom: 1rem;
}

.tts-footer__logo img {
	height: 34px;
	width: auto;
}

.tts-footer__legal {
	border-top: 1px solid var(--line-navy);
	background: var(--navy-2);
}

.tts-footer__legal-inner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	padding-block: 1.25rem;
}

.tts-footer__legal ul {
	display: flex;
	flex-wrap: wrap;
	gap: 1.25rem;
}

.tts-footer__legal li + li { margin-top: 0; }

.tts-address { font-style: normal; }
.tts-address p { margin-bottom: 0.5rem; }

/* 9. Hero ================================================================== */

.tts-hero {
	background: var(--navy);
	color: #e8eef7;
	padding-block: calc(var(--space-section) * 1.15);
}

.tts-hero__inner {
	display: grid;
	grid-template-columns: 1.15fr 1fr;
	gap: 3.5rem;
	align-items: center;
}

.tts-hero h1 {
	color: var(--white);
	max-width: 16ch;
}

.tts-hero__lede {
	font-size: var(--step-1);
	color: #cfdaea;      /* 11.02:1 on --navy */
	max-width: 52ch;
}

.tts-hero__media img {
	border-radius: var(--radius);
	box-shadow: var(--shadow);
}

/* Interior page headers — services, locations, about, blog. Shorter than the
   homepage hero and never carrying an image. */
.tts-pagehead {
	background: var(--navy);
	color: #cfdaea;
	padding-block: calc(var(--space-section) * 0.7);
}

.tts-pagehead h1 { max-width: 22ch; }

.tts-pagehead__lede {
	font-size: var(--step-1);
	color: #cfdaea;
	max-width: var(--measure);
}

/* Breadcrumbs, matching the BreadcrumbList schema on the same page. */
.tts-crumbs {
	font-size: var(--step--1);
	margin-bottom: 1.25rem;
}

.tts-crumbs ol {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	list-style: none;
	margin: 0;
	padding: 0;
}

.tts-crumbs li + li::before {
	content: "/";
	margin-right: 0.5rem;
	opacity: 0.55;
}

.tts-pagehead .tts-crumbs a { color: #cfdaea; }

/* 10. Cards and grids ====================================================== */

.tts-grid { display: grid; gap: 1.75rem; }

.tts-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.tts-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.tts-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.tts-card {
	position: relative;
	display: flex;
	flex-direction: column;
	background: var(--white);
	border: 1px solid var(--line);
	border-radius: var(--radius);
	padding: 1.75rem;
	transition: box-shadow 0.18s ease, transform 0.18s ease;
}

.tts-card:hover {
	box-shadow: var(--shadow);
	transform: translateY(-2px);
}

/* h2 or h3 — whichever is correct for the outline at the call site. The
   front-page cards sit under an h2 ("What We Do") and are correctly h3; the
   /services/ hub has nothing between its h1 and the cards, so its cards are
   h2. Same visual component, different heading level depending on what
   precedes it — the class carries the style, the markup carries the level. */
.tts-card :is(h2, h3) { margin-bottom: 0.5rem; }

.tts-card :is(h2, h3) a {
	color: var(--ink);
	text-decoration: none;
}

/* The whole card is clickable, but only the heading link is in the tab order.
   Wrapping an <a> around a heading plus body copy produces one enormous,
   unreadable accessible name. */
.tts-card :is(h2, h3) a::after {
	content: "";
	position: absolute;
	inset: 0;
}

.tts-card p {
	color: var(--muted-text);
	flex: 1;
}

.tts-card__more {
	margin-top: 1.15rem;
	font-family: var(--font-head);
	font-weight: 600;
	font-size: var(--step--1);
	color: var(--red-text-aaa);
	text-decoration: none;
}

.tts-card--navy {
	background: var(--navy-band);
	border-color: transparent;
	color: #cfdaea;
}

.tts-card--navy :is(h2, h3, h2 a, h3 a) { color: var(--white); }
.tts-card--navy p { color: #cfdaea; }

.tts-card__icon {
	width: 44px;
	height: 44px;
	margin-bottom: 1rem;
	color: var(--red);
}

/* A list of deliverables — service pages. */
.tts-ticklist {
	list-style: none;
	padding: 0;
	margin: 1.5rem 0 0;
	display: grid;
	gap: 0.65rem;
}

.tts-ticklist li {
	position: relative;
	padding-left: 1.85rem;
	color: var(--body);
}

.tts-ticklist li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.5em;
	width: 0.7rem;
	height: 0.7rem;
	border-radius: 2px;
	background: var(--red);
}

.tts-section--navy .tts-ticklist li,
.tts-section--band .tts-ticklist li { color: #cfdaea; }

.tts-section--navy .tts-ticklist li::before,
.tts-section--band .tts-ticklist li::before { background: var(--red-on-navy); }

/* Small factual chips — standards, counties, technologies. */
.tts-chips {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	list-style: none;
	margin: 1.25rem 0 0;
	padding: 0;
}

.tts-chips li {
	font-family: var(--font-head);
	font-size: var(--step--1);
	font-weight: 600;
	padding: 0.35rem 0.8rem;
	border-radius: 999px;
	background: var(--paper);
	border: 1px solid var(--line);
	color: var(--ink);
}

.tts-section--navy .tts-chips li,
.tts-section--band .tts-chips li {
	background: rgba(255, 255, 255, 0.09);
	border-color: rgba(255, 255, 255, 0.22);
	color: var(--white);
}

/* 11. Sections ============================================================= */

/* --- Testimonials -------------------------------------------------------
   A static grid, not a carousel. The live site autoplays a Swiper carousel
   every 4 seconds with no pause control and no accessible name, and pulls a
   40 KB bundle to do it. Three quotes fit on one row. */
.tts-quote {
	background: var(--white);
	border: 1px solid var(--line);
	border-left: 3px solid var(--red);
	border-radius: var(--radius);
	padding: 1.75rem;
	margin: 0;
	display: flex;
	flex-direction: column;
}

.tts-quote__text {
	font-size: var(--step-0);
	color: var(--ink);
	margin-bottom: 1.15rem;
	flex: 1;
}

.tts-quote__cite {
	font-style: normal;
	font-size: var(--step--1);
	color: var(--muted-text);
	display: block;
}

.tts-quote__name {
	display: block;
	font-family: var(--font-head);
	font-weight: 600;
	color: var(--ink);
}

/* --- FAQ ----------------------------------------------------------------
   Native <details>, open by default. An answer engine reads the DOM, and a
   collapsed answer that needs JavaScript to reveal is an answer that may never
   be read. Users can collapse them; crawlers get the text either way. */
.tts-faq { max-width: var(--measure); }

.tts-faq__item {
	border-bottom: 1px solid var(--line);
	padding-block: 1.25rem;
}

.tts-faq__item summary {
	font-family: var(--font-head);
	font-size: var(--step-1);
	font-weight: 600;
	color: var(--ink);
	cursor: pointer;
	list-style: none;
	display: flex;
	justify-content: space-between;
	align-items: flex-start;
	gap: 1rem;
}

.tts-faq__item summary::-webkit-details-marker { display: none; }

.tts-faq__item summary::after {
	content: "+";
	font-size: 1.4em;
	line-height: 1;
	color: var(--red-text-aaa);
	flex-shrink: 0;
}

.tts-faq__item[open] summary::after { content: "–"; }

.tts-faq__answer {
	margin-top: 0.85rem;
	color: var(--body);
	max-width: var(--measure);
}

/* --- CTA band ----------------------------------------------------------- */
.tts-cta {
	background: var(--navy-band);
	color: #e8eef7;
	padding-block: calc(var(--space-section) * 0.8);
	text-align: center;
}

.tts-cta h2 {
	color: var(--white);
	margin-inline: auto;
	max-width: 22ch;
}

.tts-cta p {
	color: #cfdaea;
	margin-inline: auto;
	max-width: 55ch;
}

.tts-cta .tts-btn-row { justify-content: center; }

/* --- Coverage list ------------------------------------------------------
   Counties, not a 33-card grid of near-identical pages. County level is the
   honest unit: it scales without inventing URLs and it implies no response
   time. */
.tts-coverage {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
	gap: 2rem;
	margin-top: 2rem;
}

/* h2, not h3: page-service-areas.php has nothing but a lede paragraph between
   its h1 and this list, and .tts-coverage has exactly the one call site. */
.tts-coverage h2 {
	font-size: var(--step-0);
	padding-bottom: 0.5rem;
	border-bottom: 2px solid var(--red);
	margin-bottom: 0.85rem;
}

.tts-coverage ul {
	list-style: none;
	padding: 0;
	margin: 0;
}

.tts-coverage li + li { margin-top: 0.4rem; }

/* 12. Blog ================================================================= */

.tts-postcard {
	position: relative;
	display: flex;
	flex-direction: column;
	background: var(--white);
	border: 1px solid var(--line);
	border-radius: var(--radius);
	overflow: hidden;
	transition: box-shadow 0.18s ease, transform 0.18s ease;
}

.tts-postcard:hover {
	box-shadow: var(--shadow);
	transform: translateY(-2px);
}

.tts-postcard__media {
	aspect-ratio: 16 / 9;
	background: var(--paper);
}

.tts-postcard__media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.tts-postcard__body {
	padding: 1.5rem;
	display: flex;
	flex-direction: column;
	flex: 1;
}

.tts-postcard__body :is(h2, h3) {
	font-size: var(--step-1);
	margin-bottom: 0.5rem;
}

.tts-postcard__body :is(h2, h3) a {
	color: var(--ink);
	text-decoration: none;
}

.tts-postcard__body :is(h2, h3) a::after {
	content: "";
	position: absolute;
	inset: 0;
}

.tts-postcard__excerpt {
	color: var(--muted-text);
	font-size: var(--step--1);
	flex: 1;
}

.tts-meta {
	font-size: var(--step--1);
	color: var(--muted-text);
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
	align-items: center;
	margin-bottom: 0.75rem;
}

/* Above the card's stretched link, so category links stay clickable. */
.tts-meta a {
	color: var(--muted-text);
	position: relative;
	z-index: 1;
}

.tts-pagination {
	display: flex;
	gap: 0.5rem;
	flex-wrap: wrap;
	justify-content: center;
	margin-top: 3rem;
}

.tts-pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.6rem;
	height: 2.6rem;
	padding-inline: 0.6rem;
	border: 1px solid var(--line);
	border-radius: var(--radius-sm);
	text-decoration: none;
	color: var(--ink);
	font-family: var(--font-head);
	font-weight: 600;
}

.tts-pagination .page-numbers.current {
	background: var(--navy);
	border-color: var(--navy);
	color: var(--white);
}

.tts-single__header {
	max-width: var(--measure);
	margin-bottom: 2rem;
}

.tts-single__media { margin-bottom: 2.5rem; }

.tts-single__media img {
	border-radius: var(--radius);
	width: 100%;
}

/* 13. Forms ================================================================ */

.tts-form {
	display: grid;
	gap: 1.25rem;
	max-width: 640px;
}

.tts-field label {
	display: block;
	font-family: var(--font-head);
	font-weight: 600;
	font-size: var(--step--1);
	color: var(--ink);
	margin-bottom: 0.4rem;
}

.tts-required { color: var(--red-text-aaa); }

.tts-field :is(input, textarea, select) {
	width: 100%;
	font-family: inherit;
	font-size: var(--step-0);
	color: var(--ink);
	padding: 0.75rem 0.9rem;
	border: 1px solid var(--muted);
	border-radius: var(--radius-sm);
	background: var(--white);
}

.tts-field :is(input, textarea, select):focus {
	outline: 3px solid var(--sky-text);
	outline-offset: 1px;
	border-color: var(--sky-text);
}

.tts-field textarea {
	min-height: 9rem;
	resize: vertical;
}

.tts-field__hint {
	font-size: var(--step--1);
	color: var(--muted-text);
	margin-top: 0.35rem;
}

/* Errors are carried by text, not by colour alone. */
.tts-field__error {
	font-size: var(--step--1);
	font-weight: 600;
	color: var(--red-text-aaa);
	margin-top: 0.35rem;
}

.tts-field--error :is(input, textarea) {
	border-color: var(--red-text-aaa);
	border-width: 2px;
}

.tts-notice {
	padding: 1rem 1.25rem;
	border-radius: var(--radius-sm);
	border-left: 4px solid;
	margin-bottom: 1.5rem;
}

.tts-notice--ok {
	background: #eef8f0;
	border-color: #1c7a3c;
	color: #14532b;      /* 8.39:1 on its background */
}

.tts-notice--error {
	background: #fdeceb;
	border-color: var(--red-text-aaa);
	color: #7d1c17;      /* 8.96:1 on its background */
}

/* The honeypot. Positioned off-screen rather than display:none — some bots
   skip hidden fields — and kept out of the tab order and the a11y tree by the
   template's tabindex/aria-hidden. */
.tts-hp {
	position: absolute !important;
	left: -9999px !important;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* 14. Utilities ============================================================ */

.tts-visually-hidden {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.tts-center { text-align: center; }
.tts-mt-0 { margin-top: 0; }
.tts-mb-0 { margin-bottom: 0; }

/* 15. Responsive ===========================================================
   The layouts above are the desktop case; these collapse them. Breakpoints sit
   where the content actually breaks, not at device widths. */

@media (max-width: 1024px) {
	.tts-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.tts-footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.tts-hero__inner { gap: 2.5rem; }
}

@media (max-width: 860px) {
	:root {
		--space-section: 56px;
		--header-h: 64px;
	}

	.tts-grid--2,
	.tts-grid--3,
	.tts-grid--4 { grid-template-columns: minmax(0, 1fr); }

	.tts-hero__inner { grid-template-columns: minmax(0, 1fr); }
	.tts-hero h1 { max-width: none; }
	.tts-hero__media { order: -1; }

	.tts-nav-toggle { display: inline-flex; }

	.tts-nav {
		position: absolute;
		inset: var(--header-h) 0 auto 0;
		background: var(--navy);
		border-top: 1px solid rgba(255, 255, 255, 0.12);
		display: none;
	}

	.tts-nav[data-open="true"] { display: block; }

	.tts-nav ul {
		flex-direction: column;
		align-items: stretch;
		gap: 0;
		padding: 0.5rem var(--gutter) 1.25rem;
	}

	.tts-nav li { border-bottom: 1px solid rgba(255, 255, 255, 0.08); }

	.tts-nav a {
		display: block;
		padding-block: 0.9rem;
		border-bottom: 0;
	}

	.tts-header__phone { display: none; }

	/* The CTA button was the confirmed cause of the sitewide 320px horizontal
	   scroll (measured 344px document width against a 320px viewport — see
	   REVIEW-FINDINGS-2026-07-26.md). flex-wrap was considered and rejected:
	   wrapping the header row drops the CTA onto its own line below the logo
	   instead of removing it, which still leaves a cramped, easy-to-mis-tap
	   target crowding the nav toggle. Hidden here, same as the phone number
	   two lines up — the nav array (inc/data.php) already has its own
	   "Contact Us" entry pointing at the same /contact-us/ destination, so the
	   Menu panel still reaches it; it just is not styled as a button there. */
	.tts-header__actions { display: none; }
}

@media (max-width: 560px) {
	.tts-footer__grid {
		grid-template-columns: minmax(0, 1fr);
		gap: 2rem;
	}

	.tts-footer__legal-inner {
		flex-direction: column;
		align-items: flex-start;
	}

	.tts-btn { width: 100%; }
	.tts-btn-row { flex-direction: column; }
}

/* 16. Motion, focus, print ================================================= */

/* A visible focus ring on everything, always. The default ring is removed by
   so many resets that stating it explicitly is the only reliable way to keep a
   site keyboard-navigable. */
:where(a, button, input, textarea, select, summary, [tabindex]):focus-visible {
	outline: 3px solid var(--sky-text);
	outline-offset: 2px;
	border-radius: 2px;
}

/* --sky-text is 3.27:1 on --navy — barely clears the 3:1 WCAG 1.4.11
   non-text floor for a focus ring and reads as faint against a dark
   surface in practice, so dark surfaces get the gold instead, which is a
   comfortable 10.08:1. */
.tts-header :focus-visible,
.tts-footer :focus-visible,
.tts-section--navy :focus-visible,
.tts-section--band :focus-visible,
.tts-cta :focus-visible,
.tts-hero :focus-visible,
.tts-pagehead :focus-visible {
	outline-color: var(--gold-on-navy);
}

@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }

	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* 17. Newsletter — Artificially Informed ==================================== */

/* Visually hidden but available to assistive tech. Same left:-9999px approach
   as .tts-skip, minus the :focus reveal — these never take focus. Used for
   <caption> on a table whose heading is already stated above it, where core
   accessibility guidance wants a caption but a visible one would duplicate. */
.tts-visually-hidden {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* Tables must scroll INSIDE their own container. A wide table that widens the
   page body is a WCAG 1.4.10 reflow failure, and the theme's rule is that the
   body never scrolls horizontally. Deliberately OPERABLE, not just
   deliberately overflowing: the markup gives this element tabindex="0",
   role="region", and aria-labelledby pointing at the table's own caption
   (see single-tts_issue.php), so a keyboard user can tab to the region and
   scroll it with arrow keys — WCAG 2.1.1 requires that any content reachable
   by mouse stay reachable without one, and overflow-x alone only reaches
   mouse and touch input. */
.tts-table-scroll {
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
}

.tts-table {
	width: 100%;
	border-collapse: collapse;
	font-size: var(--step--1);
}

.tts-table caption {
	text-align: left;
	font-family: var(--font-head);
	font-weight: 700;
	font-size: var(--step-0);
	color: var(--ink);
	padding-bottom: 0.75rem;
}

.tts-table__range {
	display: block;
	font-weight: 400;
	font-size: var(--step--1);
	color: var(--muted-text);
}

.tts-table th,
.tts-table td {
	text-align: left;
	padding: 0.7rem 0.9rem;
	border-bottom: 1px solid var(--line);
	vertical-align: top;
}

.tts-table thead th {
	font-family: var(--font-head);
	font-size: var(--step--1);
	color: var(--muted-text);
	border-bottom-width: 2px;
	white-space: nowrap;
}

.tts-table tbody th {
	font-weight: 600;
	color: var(--ink);
	white-space: nowrap;
}

/* --- Issue page --- */

.tts-issue__toc ul {
	list-style: none;
	padding-left: 0;
	margin: 0;
	display: grid;
	gap: 0.5rem;
}

.tts-issue__story + .tts-issue__story {
	margin-top: 3.5rem;
	padding-top: 3.5rem;
	border-top: 1px solid var(--line);
}

.tts-issue__headline {
	margin-bottom: 0.4rem;
}

/* The plain-language restatement under a deliberately punning headline. Styled
   as a lede rather than as small print: it is the sentence that tells a reader
   in a hurry — and a retrieval system chunking this page — what the story
   actually is. */
.tts-issue__dek {
	font-size: var(--step-1);
	line-height: 1.45;
	color: var(--muted-text);
	margin-top: 0;
	margin-bottom: 1.5rem;
}

.tts-issue__image {
	border-radius: var(--radius);
	margin-bottom: 1.5rem;
}

.tts-issue__source,
.tts-issue__fine {
	font-size: var(--step--1);
	color: var(--muted-text);
}

.tts-issue__ceo {
	border-left: 4px solid var(--red);
	padding-left: 1.5rem;
}

.tts-issue__byline {
	font-family: var(--font-head);
	font-weight: 600;
	color: var(--ink);
}

.tts-issue__pager {
	list-style: none;
	padding-left: 0;
	margin: 0 0 1rem;
	display: flex;
	flex-wrap: wrap;
	gap: 1.5rem;
	justify-content: space-between;
}

.tts-issue__pager-next { margin-left: auto; text-align: right; }

/* --- Hub --- */

.tts-issue-card {
	border: 1px solid var(--line);
	border-radius: var(--radius);
	padding: 2rem;
}

.tts-issue-card--latest { border-left: 4px solid var(--red); }

.tts-issue-card h2 { margin-top: 0.25rem; }

.tts-issue-card__subject { color: var(--muted-text); }

.tts-issue-card__stories {
	margin: 1.25rem 0 0;
	padding-left: 1.2em;
	display: grid;
	gap: 0.45rem;
}

/* --- Subscribe --- */

/* The compact variant single.php passes at the foot of a blog post — same
   form, sized to sit under an article rather than anchor a full section the
   way it does on the hub and on every issue. */
.tts-subscribe--compact .tts-subscribe__title {
	font-size: var(--step-1);
	margin-bottom: 0.35em;
}

.tts-subscribe--compact .tts-subscribe__lede {
	font-size: var(--step--1);
	color: var(--muted-text);
}

.tts-subscribe--compact .tts-subscribe__form { margin-top: 0.85rem; }

.tts-subscribe__form { margin-top: 1.25rem; }

.tts-subscribe__row {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
	align-items: center;
}

/* The visible <label> is required — a placeholder is not an accessible name,
   and it disappears the moment the field has content. Kept off the flex row so
   it sits above the input rather than beside it. */
.tts-subscribe__label {
	flex: 1 0 100%;
	font-family: var(--font-head);
	font-weight: 600;
	font-size: var(--step--1);
}

.tts-subscribe__input {
	flex: 1 1 18rem;
	min-width: 0;
	padding: 0.7rem 0.9rem;
	/* var(--muted), not var(--line) — matches .tts-field's own input border
	   (style.css:1193). var(--line) measures 1.24:1 against the field's white
	   background, well under the 3:1 floor WCAG 1.4.11 sets for UI component
	   boundaries; var(--muted) measures 6.66:1 here. */
	border: 1px solid var(--muted);
	border-radius: var(--radius-sm);
	font: inherit;
	font-size: var(--step-0);
	color: var(--ink);
	background: var(--white);
}

.tts-subscribe__fine {
	font-size: var(--step--1);
	color: var(--muted-text);
	margin-top: 0.75rem;
}

/* On dark surfaces the label and fine print need the light text tokens, and the
   input keeps a white field so the typed value stays high-contrast. */
.tts-section--navy .tts-subscribe__label,
.tts-section--band .tts-subscribe__label,
.tts-cta .tts-subscribe__label { color: var(--white); }

.tts-section--navy .tts-subscribe__fine,
.tts-section--band .tts-subscribe__fine,
.tts-cta .tts-subscribe__fine { color: #cfdaea; }

@media print {
	.tts-header,
	.tts-footer,
	.tts-cta,
	.tts-nav-toggle,
	.tts-subscribe,
	.tts-skip { display: none !important; }

	body {
		color: #000;
		font-size: 11pt;
	}

	a[href^="http"]::after {
		content: " (" attr(href) ")";
		font-size: 0.85em;
		word-break: break-all;
	}
}
