/*
Theme Name: Say It SEO
Theme URI: https://sayitseo.com
Author: Digital Blocks
Author URI: https://digitalblocks.ca
Description: Block theme for sayitseo.com, cloned from the Digital Blocks starter. theme.json is the design system; bias hard toward less code.
Version: 1.0.6
Requires at least: 7.1
Tested up to: 7.1
Requires PHP: 8.2
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: sayitseo
*/

/*
 * Every rule below is here because theme.json could not express it; the
 * comment above each one says why. Colours, fonts and sizes still come from
 * theme.json presets (var(--wp--preset--*)), never new values.
 * The 600px media queries mirror settings.viewport.mobile in theme.json.
 */

/* Slug collision guard. The palette slug "border" (a contract with the
   sayitseo-core plugin) makes core generate the text-colour class
   .has-border-color { color: … !important }, and core also adds
   .has-border-color to every block that has a border colour, so bordered
   cards would get line-grey text. theme.json cannot rename a generated class.
   Blocks that set a real text colour also carry .has-text-color and keep it
   (and "border" is first in the palette so their colour class wins). */
.has-border-color:not(.has-text-color) {
	color: inherit !important;
}

/* Links: underline weight and offset. theme.json typography has
   textDecoration but no text-decoration-thickness or text-underline-offset. */
a {
	text-decoration-thickness: 2px;
	text-underline-offset: 0.28em;
}

/* The current page in the menu: underline the link itself, so it matches a
   hovered link and hovering it doesn't add a second line. theme.json's
   "-current" state styles the list item instead, which drew two underlines
   (one on the item, one on the hovered link) at different offsets. */
.wp-block-navigation .current-menu-item > a {
	text-decoration: underline;
}

/* Headings wrap in balanced lines, as in the design. theme.json has no
   text-wrap property. */
h1,
h2 {
	text-wrap: balance;
}

/* The highlighter: a lime band behind the words. theme.json has no `mark`
   element. Core's Highlight format also outputs <mark> (with the
   has-inline-color class and an inline colour), so those are left alone. */
mark:not(.has-inline-color) {
	padding: 0 0.08em;
	color: var(--wp--preset--color--contrast);
	background: linear-gradient(transparent 14%, var(--wp--preset--color--primary) 14% 90%, transparent 90%);
	-webkit-box-decoration-break: clone;
	box-decoration-break: clone;
}

/* Strikethrough (core format, <s>) is drawn in coral: "crossed out" is the
   accent's one job. theme.json cannot set text-decoration-color/thickness. */
s {
	text-decoration-color: var(--wp--preset--color--accent);
	text-decoration-thickness: 0.12em;
}

/* Header: the log-in link and the button never break mid-label. French labels
   run long, and a wrapped "Se connecter" or "Commen-cer" reads as broken; the
   menu's own items wrap instead. theme.json has no white-space property. */
header.wp-block-template-part .wp-block-button__link,
header.wp-block-template-part p a {
	white-space: nowrap;
}

/* Brand lockup (header and footer patterns, inside a core/html block).
   theme.json cannot reach markup inside an HTML block, and the lockup mixes
   two fonts in one link. */
.sayitseo-brand {
	display: inline-flex;
	gap: 10px;
	align-items: center;
	color: var(--wp--preset--color--contrast);
	text-decoration: none;
}

.sayitseo-brand > svg {
	flex: none;
	width: 34px;
	height: 34px;
}

.sayitseo-brand__name {
	font-family: var(--wp--preset--font-family--display);
	font-size: 1.375rem;
	font-weight: 800;
	line-height: 1;
	letter-spacing: -0.03em;
	white-space: nowrap;
}

.sayitseo-brand__seo {
	margin-left: 0.35em;
	font-family: var(--wp--preset--font-family--body);
	font-size: 0.52em;
	font-weight: 700;
	letter-spacing: 0.3em;
	color: var(--wp--preset--color--secondary);
}

.sayitseo-brand.is-on-dark {
	color: var(--wp--preset--color--base);
}

.sayitseo-brand.is-on-dark .sayitseo-brand__seo {
	color: var(--wp--preset--color--primary);
}

/* Decorative SVGs (play button, S connector, phone icon) sit in core/html
   blocks inside flex rows; the HTML block has no sizing controls, so stop
   them shrinking next to long text. */
.wp-block-group.is-layout-flex > svg {
	flex: none;
}

/* FAQ rows (core/details). theme.json cannot style <summary> separately from
   the answer, nor replace the disclosure triangle with the +/− icon. */
.wp-block-details > summary {
	display: flex;
	gap: 1rem;
	align-items: center;
	justify-content: space-between;
	box-sizing: border-box;
	min-height: 64px;
	padding-block: 0.875rem;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--lead);
	font-weight: 700;
	line-height: 1.3;
	list-style: none;
	cursor: pointer;
}

.wp-block-details > summary::-webkit-details-marker {
	display: none;
}

.wp-block-details > summary::after {
	flex: none;
	width: 22px;
	height: 22px;
	content: "";
	background: currentcolor;
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 12h12M12 6v12' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 12h12M12 6v12' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
}

.wp-block-details[open] > summary::after {
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 12h12' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'/%3E%3C/svg%3E");
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 12h12' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'/%3E%3C/svg%3E");
}

.wp-block-details[open] {
	padding-bottom: 1.25rem;
}

/* List styles registered in functions.php ("Plain", "Ruled rows").
   theme.json cannot set list-style or style individual list items. */
.wp-block-list:is(.is-style-plain, .is-style-ruled) {
	padding-left: 0;
	list-style: none;
}

.wp-block-list.is-style-plain > li + li {
	margin-top: 0.5rem;
}

.wp-block-list.is-style-ruled {
	border-bottom: 1px solid var(--wp--preset--color--contrast);
}

.wp-block-list.is-style-ruled > li {
	padding-block: 1rem;
	border-top: 1px solid var(--wp--preset--color--contrast);
}

/* Tables are ruled rows, not boxed cells (2px ink under the header, 1px lines
   between rows). theme.json can style the table block but not its cells. */
.wp-block-table th,
.wp-block-table td {
	padding: 0.875rem 0.75rem;
	text-align: left;
	vertical-align: top;
	border: 0;
	border-bottom: 1px solid var(--wp--preset--color--border);
}

.wp-block-table :is(th, td):first-child {
	padding-left: 0;
}

.wp-block-table thead {
	border-bottom: 2px solid var(--wp--preset--color--contrast);
}

.wp-block-table thead th {
	font-family: var(--wp--preset--font-family--display);
	font-weight: 800;
	border-bottom: 0;
}

.wp-block-table tbody th {
	font-weight: 600;
}

/* Pricing comparison: keep four columns readable and let the table scroll
   sideways on phones (core already sets overflow-x on the figure). */
.sis-compare table {
	min-width: 37.5rem;
}

.sis-compare thead th:first-child {
	font-family: var(--wp--preset--font-family--body);
	font-weight: 600;
	color: var(--wp--preset--color--muted);
}

/*
 * How it works S-spine (patterns home-how-it-works and hiw-steps).
 * Steps hang off a centre S-curve with a dot each (lime = the customer's step,
 * "is-you"), alternating sides; on phones the spine moves to the left with all
 * text to its right. This is drawing, not layout: no block, theme.json setting
 * or 7.1 responsive override can draw a curve between siblings or alternate
 * columns by position, so it is the one place the design needs real CSS.
 */
.sis-spine {
	--sis-spine-w: clamp(64px, 11vw, 150px);
}

.sis-spine > .sis-step {
	position: relative;
	display: grid;
	grid-template-columns: minmax(0, 1fr) var(--sis-spine-w) minmax(0, 1fr);
	column-gap: clamp(12px, 2.4vw, 32px);
	align-items: start;
}

.sis-spine > .sis-step > * {
	grid-row: 1;
	margin-block: 0;
}

.sis-spine > .sis-step:nth-child(odd) > :first-child {
	grid-column: 1;
	text-align: right;
}

.sis-spine > .sis-step:nth-child(odd) > :nth-child(2) {
	grid-column: 3;
}

.sis-spine > .sis-step:nth-child(even) > :first-child {
	grid-column: 3;
}

.sis-spine > .sis-step:nth-child(even) > :nth-child(2) {
	grid-column: 1;
}

/* The curve from this step's dot down to the next step's dot. */
.sis-spine > .sis-step:not(:last-child)::before {
	position: absolute;
	top: 9px;
	bottom: -9px;
	left: calc(50% - var(--sis-spine-w) / 2);
	width: var(--sis-spine-w);
	content: "";
	background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' preserveAspectRatio='none'%3E%3Cpath d='M30 0C30 55 70 45 70 100' fill='none' stroke='%23161A17' stroke-width='3' stroke-linecap='round' vector-effect='non-scaling-stroke'/%3E%3C/svg%3E") 0 0 / 100% 100% no-repeat;
}

.sis-spine > .sis-step:nth-child(even):not(:last-child)::before {
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' preserveAspectRatio='none'%3E%3Cpath d='M70 0C70 55 30 45 30 100' fill='none' stroke='%23161A17' stroke-width='3' stroke-linecap='round' vector-effect='non-scaling-stroke'/%3E%3C/svg%3E");
}

/* The dot: at 30% of the spine column on odd steps, 70% on even steps. */
.sis-spine > .sis-step::after {
	position: absolute;
	top: 0;
	left: calc(50% - var(--sis-spine-w) * 0.2 - 9px);
	box-sizing: border-box;
	width: 18px;
	height: 18px;
	content: "";
	background: var(--wp--preset--color--contrast);
	border-radius: 50%;
}

.sis-spine > .sis-step:nth-child(even)::after {
	left: calc(50% + var(--sis-spine-w) * 0.2 - 9px);
}

.sis-spine > .sis-step.is-you::after {
	background: var(--wp--preset--color--primary);
	border: 2.5px solid var(--wp--preset--color--contrast);
}

@media (width <= 600px) {

	.sis-spine {
		--sis-spine-w: 36px;
	}

	.sis-spine > .sis-step {
		grid-template-columns: var(--sis-spine-w) minmax(0, 1fr);
		column-gap: 0.875rem;
	}

	.sis-spine > .sis-step:nth-child(n) > :first-child {
		grid-row: 1;
		grid-column: 2;
		text-align: left;
	}

	.sis-spine > .sis-step:nth-child(n) > :nth-child(2) {
		grid-row: 2;
		grid-column: 2;
		margin-top: 1.25rem;
	}

	.sis-spine > .sis-step:not(:last-child)::before {
		left: 0;
	}

	.sis-spine > .sis-step::after {
		left: calc(var(--sis-spine-w) * 0.3 - 9px);
	}

	.sis-spine > .sis-step:nth-child(even)::after {
		left: calc(var(--sis-spine-w) * 0.7 - 9px);
	}
}

/* Scrolling down, each dot fills lime as its step reaches the middle of the
   screen. A scroll-driven animation: no theme.json setting or block can tie a
   colour to scroll position. Browsers without it, and visitors who ask for
   reduced motion, keep the dots above. */
@supports (animation-timeline: view()) {

	@media (prefers-reduced-motion: no-preference) {

		.sis-spine > .sis-step {
			view-timeline: --sis-step block;
		}

		.sis-spine > .sis-step::after,
		.sis-spine > .sis-step.is-you::after {
			border: 2.5px solid var(--wp--preset--color--contrast);
			animation: sis-dot-fill linear both;
			animation-timeline: --sis-step;
			animation-range: cover 42vh cover 52vh;
		}
	}
}

/* Home, "sounds like nobody" (pattern home-problem, "sis-strike"): as the two
   quotes scroll up the screen, a coral line is drawn through the generic AI
   sentence, then the electrician's line fades up. Scroll-driven animation, which
   theme.json and blocks can't express. Without it, or with reduced motion, the
   sentence stays struck through (the <s> rule above) and both quotes show. */
@supports (animation-timeline: view()) {

	@media (prefers-reduced-motion: no-preference) {

		.sis-strike {
			view-timeline: --sis-strike block;
		}

		.sis-strike s {
			text-decoration: none;
			background: linear-gradient(var(--wp--preset--color--accent), var(--wp--preset--color--accent)) 0 58% / 0% 0.12em no-repeat;
			animation: sis-strike-through linear both;
			animation-timeline: --sis-strike;
			animation-range: cover 25vh cover 50vh;
		}

		.sis-strike > :last-child {
			animation: sis-reveal linear both;
			animation-timeline: --sis-strike;
			animation-range: cover 48vh cover 66vh;
		}
	}
}

@keyframes sis-strike-through {

	from {
		background-size: 0% 0.12em;
	}

	to {
		background-size: 100% 0.12em;
	}
}

@keyframes sis-reveal {

	from {
		opacity: 0;
		transform: translateY(1.25rem);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

@keyframes sis-dot-fill {

	from {
		background-color: var(--wp--preset--color--contrast);
	}

	to {
		background-color: var(--wp--preset--color--primary);
	}
}

/*
 * How it works, step 3: the example call as speech bubbles (pattern hiw-steps,
 * "sis-chat"). Say It on the left with its mark, the owner on the right with a
 * photo, and a call banner and sound-wave marks so it reads as a phone call, not
 * texting. The owner's bubble is lime because their own words are the lime
 * highlighter everywhere else. Bubbles, avatars and alignment by speaker are
 * drawing on class hooks, which theme.json can't express.
 */
.sis-chat {
	display: flex;
	flex-direction: column;
	gap: 0.875rem;
}

.sis-chat > * {
	margin-block: 0;
}

.sis-chat__call {
	display: flex;
	gap: 0.5rem;
	align-items: center;
	align-self: flex-start;
	padding: 0.375rem 0.75rem;
	color: var(--wp--preset--color--contrast);
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--wp--preset--color--border);
	border-radius: 10px;
}

/* A live-call dot before the banner text, a sound wave after it. */
.sis-chat__call::before {
	flex: none;
	width: 9px;
	height: 9px;
	content: "";
	background: var(--wp--preset--color--primary);
	border: 2px solid var(--wp--preset--color--contrast);
	border-radius: 50%;
}

.sis-chat__call::after,
.sis-chat__msg > :first-child::after {
	flex: none;
	width: 22px;
	height: 12px;
	content: "";
	background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 12'%3E%3Cg stroke='%23565B55' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M2 5v2M6 3v6M10 1v10M14 4v4M18 2v8'/%3E%3C/g%3E%3C/svg%3E") center / contain no-repeat;
}

.sis-chat__call > * {
	margin: 0;
}

.sis-chat__msg {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 0.25rem;
	align-items: flex-start;
	align-self: flex-start;
	max-width: min(88%, 30rem);
	padding-left: 46px;
}

.sis-chat__msg.is-you {
	align-items: flex-end;
	align-self: flex-end;
	padding-right: 46px;
	padding-left: 0;
}

/* Avatar, level with the bottom of the bubble. */
.sis-chat__msg::before {
	position: absolute;
	bottom: 0;
	left: 0;
	width: 36px;
	height: 36px;
	content: "";
	background: url("assets/images/favicon.svg") center / cover no-repeat;
	border-radius: 50%;
}

.sis-chat__msg.is-you::before {
	right: 0;
	left: auto;
	background-image: url("assets/images/hiw-owner.webp");
	border: 2px solid var(--wp--preset--color--contrast);
}

.sis-chat__msg > * {
	margin-block: 0;
}

/* Speaker name, with the sound wave after it. */
.sis-chat__msg > :first-child {
	display: inline-flex;
	gap: 0.375rem;
	align-items: center;
	padding-inline: 0.25rem;
}

/* The bubble: the corner nearest the avatar is tighter, like a speech tail. */
.sis-chat__msg > :last-child {
	padding: 0.625rem 0.875rem;
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--wp--preset--color--border);
	border-radius: 18px 18px 18px 4px;
}

.sis-chat__msg.is-you > :last-child {
	color: var(--wp--preset--color--contrast);
	background: var(--wp--preset--color--primary);
	border-color: var(--wp--preset--color--contrast);
	border-radius: 18px 18px 4px;
}

@media (width <= 600px) {

	.sis-chat__msg {
		max-width: 94%;
	}
}

