/*
Theme Name:  North Fort Workshop
Theme URI:   https://northfortsoftware.com
Author:      North Fort Software LLC
Author URI:  https://northfortsoftware.com
Description: The North Fort Software site theme. A well-kept workbench: warm paper, copper accent, Poppins for structure and Source Serif for reading. Menu-driven navigation, no hardcoded pages, light and dark from one token set.
Version:     1.0.0
Requires at least: 6.5
Tested up to: 7.1
Requires PHP: 8.1
License:     GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: north-fort-workshop
Tags:        one-column, custom-menu, custom-logo, accessibility-ready, translation-ready
*/

/* ==========================================================================
   1. TOKENS

   THE ONLY PLACE A HEX VALUE IS WRITTEN. Everything below this block uses
   var(--token). The spec is explicit about it, and the reason is the one
   that bit the old site: a literal colour buried in a component is a colour
   nobody re-checks when the palette changes, and it is exactly where a
   contrast failure survives a redesign.
   ========================================================================== */

:root {
	--paper:      #F6F1E9;
	--paper-2:    #FFFCF6;
	--ink:        #2B2622;
	--ink-2:      #5C534B;
	--rule:       #E2D8CA;
	--copper:     #9A4E1C;
	--teal:       #2F5D62;
	--on-accent:  #FFFFFF;

	--display: 'Poppins', Arial, sans-serif;
	--body:    'Source Serif 4', Georgia, serif;

	/* Layout. Named so a template never guesses a number. */
	--page-max:    1040px;
	--hero-max:     760px;
	--measure:       65ch;
	--gutter:        16px;
	--section-gap:   60px;
	--section-gap-s: 36px;
}

/* Dark follows the system setting, and can be overridden by a toggle later.
   Both forms are defined now so adding the toggle is a data attribute and
   no CSS. The :not([data-theme="light"]) guard is what lets an explicit
   light choice win over a dark system preference. */
@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) {
		--paper:     #1E1A17;
		--paper-2:   #27221E;
		--ink:       #F2EBE1;
		--ink-2:     #C2B6A8;
		--rule:      #3B342E;
		--copper:    #E0915A;
		--teal:      #7FB6B9;
		--on-accent: #1E1A17;
		color-scheme: dark;
	}
}

:root[data-theme="dark"] {
	--paper:     #1E1A17;
	--paper-2:   #27221E;
	--ink:       #F2EBE1;
	--ink-2:     #C2B6A8;
	--rule:      #3B342E;
	--copper:    #E0915A;
	--teal:      #7FB6B9;
	--on-accent: #1E1A17;
	color-scheme: dark;
}

/* ==========================================================================
   2. BASE
   ========================================================================== */

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

html {
	/* Anchor links and skip-link targets land below the top edge rather than
	   flush against it. */
	scroll-padding-top: 24px;
}

body {
	margin: 0;
	background: var(--paper);
	color: var(--ink);
	font-family: var(--body);
	font-size: 18px;
	line-height: 1.65;
	-webkit-text-size-adjust: 100%;
	text-rendering: optimizeLegibility;
}

/* The gutter sits on the inner wrapper, not on body, so a full-bleed
   section can still reach the viewport edge. env() keeps content clear of
   a phone's rounded corners and camera notch in landscape. */
/* The max-width includes the gutters, so the wrapper's INNER edge lands at
   1040px — the same place the content grid's wide track starts. Capped at a
   bare 1040 instead, the padding pushes text 16px inward and the hero sits
   out of line with the body copy beneath it, which is visible and wrong. */
.nfw-wrap {
	max-width: calc(var(--page-max) + var(--gutter) * 2);
	margin-inline: auto;
	padding-inline: max(var(--gutter), env(safe-area-inset-left, 0px))
	                max(var(--gutter), env(safe-area-inset-right, 0px));
}

/* Headings. Poppins for structure; the serif is for reading, not labelling. */
h1, h2, h3, h4, h5, h6 {
	font-family: var(--display);
	font-weight: 600;
	color: var(--ink);
	margin: 0;
	line-height: 1.2;
}

h1 {
	font-size: clamp(34px, 6vw, 54px);
	line-height: 1.08;
	letter-spacing: -0.02em;
	text-wrap: balance;
}

h2 {
	font-size: 30px;
	text-wrap: balance;
}

h3 { font-size: 18px; }
h4 { font-size: 17px; }

p, ul, ol, dl, blockquote, figure, table, pre {
	margin: 0;
}

/* Reading measure. Applied to text, never to images or tables, which have
   their own widths. */
p, li, dd, blockquote {
	max-width: var(--measure);
}

/* A link inside running text keeps its underline. Removing it leaves colour
   as the only signal, which fails for anyone who cannot distinguish it. */
a {
	color: var(--copper);
	text-underline-offset: 2px;
}

a:hover {
	text-decoration-thickness: 2px;
}

/* Focus is visible on everything, always. :focus-visible so a mouse click
   does not leave a ring behind, while keyboard focus always shows one. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
	outline: 3px solid var(--teal);
	outline-offset: 3px;
}

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

/* Sharp corners are a rule, not a default. WordPress blocks and plugins
   bring their own radii, so this states it rather than assuming. */
img, button, input, select, textarea,
.wp-block-image img,
.wp-block-button__link {
	border-radius: 0;
}

hr, .wp-block-separator {
	border: 0;
	border-top: 1px solid var(--rule);
	margin-block: var(--section-gap);
}

/* ==========================================================================
   3. SKIP LINK

   First focusable element on the page. Moved off-screen rather than
   display:none, because a hidden element cannot receive focus at all.
   ========================================================================== */

.nfw-skip {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 100;
	background: var(--copper);
	color: var(--on-accent);
	font-family: var(--display);
	font-size: 16px;
	padding: 10px 16px;
	text-decoration: none;
}

.nfw-skip:focus {
	left: 12px;
	top: 12px;
}

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

/* ==========================================================================
   4. HEADER AND NAVIGATION

   The nav wraps to a second line rather than collapsing behind a button.
   With three items that is the simpler, more reliable behaviour: no
   JavaScript, nothing to open, nothing that can fail to open. If the menu
   grows past about five items this needs revisiting.
   ========================================================================== */

.nfw-header {
	display: flex;
	align-items: center;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: 16px;
	padding-block: 22px;
	border-bottom: 1px solid var(--rule);
}

.nfw-logo {
	display: inline-flex;
	align-items: center;
	text-decoration: none;
	line-height: 0;
}

.nfw-logo img {
	height: 46px;
	width: auto;
}

/* The reverse logo is a second <img> inside <picture>; only one ever
   renders. Swapping via CSS filters would recolour the artwork rather than
   use the file the designer drew. */
@media (max-width: 420px) {
	.nfw-logo img { height: 38px; }
}

.nfw-nav {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 22px;
	font-family: var(--display);
	font-size: 15px;
}

.nfw-nav ul {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 22px;
	list-style: none;
	margin: 0;
	padding: 0;
	max-width: none;
}

.nfw-nav li {
	max-width: none;
}

.nfw-nav a {
	color: var(--ink);
	text-decoration: none;
}

.nfw-nav a:hover {
	color: var(--copper);
}

/* The current page is marked with colour AND weight, so colour is not
   carrying it alone. */
.nfw-nav .current-menu-item > a,
.nfw-nav [aria-current="page"] {
	color: var(--copper);
	font-weight: 500;
}

/* ==========================================================================
   5. BUTTONS
   ========================================================================== */

.nfw-btn {
	display: inline-block;
	font-family: var(--display);
	font-size: 16px;
	font-weight: 500;
	line-height: 1.2;
	padding: 12px 20px;
	text-decoration: none;
	border: 1px solid transparent;
	cursor: pointer;
	max-width: none;
}

.nfw-btn--primary {
	background: var(--copper);
	color: var(--on-accent);
	border-color: var(--copper);
}

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

/* The header's Open Glassdraw button is the same button, smaller, so it sits
   on the nav line without crowding it. */
.nfw-btn--small {
	font-size: 15px;
	padding: 8px 14px;
}

/* ==========================================================================
   6. CONTENT LAYOUT

   A grid with named lines, so .alignwide and .alignfull escape the reading
   column without negative margins. Negative margins are the usual trick and
   they overflow on narrow screens, which is how a page ends up with a
   horizontal scrollbar on a phone.
   ========================================================================== */

/*
 * Three widths from one grid: content (760), wide (1040), full (viewport).
 *
 * TWO THINGS HERE WERE WRONG FIRST TIME AND ARE WORTH NAMING.
 *
 * 1. The content track was minmax(0, 760px) with a 140px track on each
 *    side. On a 320px phone those side tracks took their full 140px each
 *    and left the reading column 8px wide — paragraphs rendered about 96px
 *    across. min() fixes it: the content track asks for 760px or whatever
 *    is left after the gutters, whichever is smaller, so it is sized before
 *    anything else can take from it.
 *
 * 2. Content was centred inside the 1040 band, which put its left edge
 *    140px right of the hero's. Everything on the page is left-aligned to
 *    the same line, so content-start and wide-start are the same line and
 *    the slack all sits in one track on the right.
 */
.nfw-content {
	--gutter-safe-l: max(var(--gutter), env(safe-area-inset-left, 0px));
	--gutter-safe-r: max(var(--gutter), env(safe-area-inset-right, 0px));

	display: grid;
	grid-template-columns:
		[full-start] minmax(var(--gutter-safe-l), 1fr)
		[wide-start content-start] min(
			var(--hero-max),
			100% - var(--gutter-safe-l) - var(--gutter-safe-r)
		) [content-end]
		minmax(0, calc(var(--page-max) - var(--hero-max))) [wide-end]
		minmax(var(--gutter-safe-r), 1fr) [full-end];
	row-gap: 24px;
}

.nfw-content > * {
	grid-column: content;
}

.nfw-content > .alignwide {
	grid-column: wide;
}

.nfw-content > .alignfull {
	grid-column: full;
	/* Full bleed is edge-to-edge for the BOX, not for text inside it. A
	   full-width table or group would otherwise start its first word hard
	   against the screen edge, which breaks the gutter rule the spec sets
	   at every width. Pictures are the exception below — a photo running
	   off both edges is the whole point of a full-bleed photo. */
	padding-inline: var(--gutter-safe-l) var(--gutter-safe-r);
}

.nfw-content > .wp-block-image.alignfull,
.nfw-content > .wp-block-gallery.alignfull,
.nfw-content > figure.alignfull:not(.wp-block-table) {
	padding-inline: 0;
}

/* Images that lead a section on the Glassdraw pages run wider than the text,
   per the spec. They keep their own width, not the reading measure. */
.nfw-content > figure,
.nfw-content > .wp-block-image,
.nfw-content > .wp-block-gallery,
.nfw-content > .wp-block-table {
	max-width: none;
}

/* A page without a hero still needs its H1, just at content scale. Dropping
   the H1 entirely would leave the page with no top-level heading, and
   setting a 54px headline over "Refund policy" is scale with nothing behind
   it. */
.nfw-content--plain {
	padding-top: 48px;
}

.nfw-title-plain {
	font-size: 34px;
	line-height: 1.15;
	letter-spacing: -0.01em;
	margin-bottom: 8px;
}

.nfw-page-links {
	font-family: var(--display);
	font-size: 15px;
	margin-top: 16px;
}

/* ==========================================================================
   7. HERO
   ========================================================================== */

.nfw-hero {
	display: grid;
	gap: 20px;
	max-width: var(--hero-max);
	padding-block: 64px 48px;
}

/* One word of the H1 may be copper. <em> carries it, with the italic
   removed: the emphasis is real, so the element is right even though the
   styling is not italic. */
.nfw-hero h1 em {
	font-style: normal;
	color: var(--copper);
}

.nfw-hero p {
	font-size: 20px;
	color: var(--ink-2);
	max-width: 60ch;
}

.nfw-label {
	display: block;
	font-family: var(--display);
	font-size: 13px;
	font-weight: 500;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--ink-2);
	max-width: none;
}

/* ==========================================================================
   8. PRODUCT CARD — "the shelf"
   ========================================================================== */

.nfw-shelf {
	display: grid;
	gap: 28px;
	padding-block: 8px 64px;
}

/* Two or more products sit side by side and wrap on their own. The
   min(100%, 420px) keeps a single card from overflowing a narrow screen,
   which a bare 420px minimum would do. */
.nfw-shelf--multi {
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr));
}

.nfw-product {
	background: var(--paper-2);
	border: 1px solid var(--rule);
	display: grid;
	align-items: center;
	min-width: 0;
}

/* One product: image left at about 56%, text right. */
.nfw-shelf--single .nfw-product {
	grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
}

.nfw-product__art {
	width: 100%;
	height: 100%;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	display: block;
}

.nfw-product__text {
	display: grid;
	gap: 12px;
	align-content: start;
	padding: 26px;
	min-width: 0;
}

.nfw-product__text h2 {
	font-size: 28px;
	line-height: 1.15;
}

.nfw-product__text p {
	color: var(--ink-2);
}

.nfw-product .nfw-btn,
.nfw-product .nfw-tag {
	justify-self: start;
}

@media (max-width: 760px) {
	.nfw-shelf--single .nfw-product {
		grid-template-columns: 1fr;
	}

	.nfw-product__art {
		border-bottom: 1px solid var(--rule);
	}
}

/* ==========================================================================
   9. TAG

   currentColor on the border means the tag takes its product's accent from
   one declaration, not two that can drift apart.
   ========================================================================== */

.nfw-tag {
	display: inline-block;
	font-family: var(--display);
	font-size: 12px;
	font-weight: 500;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--copper);
	border: 1px solid currentColor;
	padding: 2px 8px;
	max-width: none;
}

/* ==========================================================================
   10. PROMISE GRID — "How we work"
   ========================================================================== */

.nfw-promise {
	border-top: 1px solid var(--rule);
	padding-block: 56px;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
	gap: 32px;
}

.nfw-promise__intro {
	grid-column: 1 / -1;
	display: grid;
	gap: 8px;
}

.nfw-promise h3 {
	margin-bottom: 6px;
}

.nfw-promise p {
	color: var(--ink-2);
	font-size: 17px;
}

/* ==========================================================================
   11. SECTIONS AND LONG-FORM CONTENT
   ========================================================================== */

.nfw-section {
	padding-block: var(--section-gap);
	border-top: 1px solid var(--rule);
}

.nfw-section:first-child {
	border-top: 0;
}

/* Spacing between blocks inside page content comes from the grid's row-gap.
   These restore a larger break before a heading, so a new section reads as
   a new section rather than another paragraph. */
.nfw-content > h2 { margin-top: 24px; }
.nfw-content > h3 { margin-top: 12px; }

.nfw-content > ul,
.nfw-content > ol {
	padding-left: 1.4em;
}

.nfw-content li + li {
	margin-top: 6px;
}

/* Numbered getting-started steps, each with a screenshot. A real <ol>, with
   the marker kept — the numbers are content, not decoration. */
.nfw-steps {
	display: grid;
	gap: 36px;
	padding-left: 1.4em;
}

.nfw-steps > li {
	max-width: none;
}

.nfw-steps h3 {
	margin-bottom: 8px;
}

.nfw-steps img {
	margin-top: 14px;
	border: 1px solid var(--rule);
}

/* ==========================================================================
   12. TABLES

   Used for the Glassdraw browser support table. Headers are real <th> with
   scope; this only styles them.
   ========================================================================== */

.nfw-content table,
.wp-block-table table {
	width: 100%;
	border-collapse: collapse;
	font-size: 17px;
	max-width: none;
}

.nfw-content th,
.wp-block-table th {
	font-family: var(--display);
	font-weight: 600;
	text-align: left;
	border-bottom: 2px solid var(--ink);
	padding: 10px 12px 8px;
	vertical-align: bottom;
}

.nfw-content td,
.wp-block-table td {
	border-bottom: 1px solid var(--rule);
	padding: 10px 12px;
	vertical-align: top;
}

.nfw-content th[scope="row"],
.wp-block-table th[scope="row"] {
	border-bottom: 1px solid var(--rule);
	font-weight: 500;
}

/* ==========================================================================
   13. GALLERY AND FIGURES
   ========================================================================== */

.wp-block-gallery.has-nested-images figure.wp-block-image figcaption,
figcaption,
.wp-element-caption {
	font-family: var(--body);
	font-size: 15px;
	color: var(--ink-2);
	margin-top: 8px;
	max-width: var(--measure);
}

.wp-block-image img {
	border: 1px solid var(--rule);
}

/* ==========================================================================
   14. FOOTER
   ========================================================================== */

.nfw-footer {
	border-top: 1px solid var(--rule);
	padding-block: 28px;
	display: flex;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: 16px;
	font-family: var(--display);
	font-size: 14px;
	color: var(--ink-2);
}

.nfw-footer ul {
	display: flex;
	flex-wrap: wrap;
	gap: 18px;
	list-style: none;
	margin: 0;
	padding: 0;
	max-width: none;
}

.nfw-footer li { max-width: none; }

.nfw-footer a {
	color: var(--ink-2);
	text-decoration: none;
}

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

/* ==========================================================================
   15. ADMIN NOTICE FOR AN UNASSIGNED MENU

   Shown only to someone who can fix it. A visitor sees nothing rather than
   a nav full of invented links.
   ========================================================================== */

.nfw-menu-missing {
	font-family: var(--display);
	font-size: 14px;
	color: var(--ink-2);
	max-width: none;
}

/* ==========================================================================
   16. SMALL SCREENS
   ========================================================================== */

@media (max-width: 520px) {
	body {
		font-size: 17px;
	}

	:root {
		--section-gap: var(--section-gap-s);
	}

	.nfw-hero {
		padding-block: 40px 32px;
	}

	.nfw-hero p {
		font-size: 19px;
	}

	h2 {
		font-size: 26px;
	}

	.nfw-nav,
	.nfw-nav ul {
		gap: 16px;
	}

	.nfw-shelf {
		padding-block: 4px 40px;
	}

	.nfw-promise {
		padding-block: 40px;
		gap: 28px;
	}
}

/* ==========================================================================
   17. MOTION AND PRINT
   ========================================================================== */

/* The design uses no motion. This is here so a block or plugin that brings
   its own animation still respects the setting. */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* Print redefines the tokens rather than overriding components. Done the
   other way, a page printed while the system is in dark mode comes out with
   a near-black background — pages of toner, and unreadable on top of that.
   Redefining here means every component already points at the right value. */
@media print {
	:root,
	:root[data-theme="dark"] {
		--paper:     #FFFFFF;
		--paper-2:   #FFFFFF;
		--ink:       #000000;
		--ink-2:     #333333;
		--rule:      #BBBBBB;
		--copper:    #000000;
		--teal:      #000000;
		--on-accent: #FFFFFF;
		color-scheme: light;
	}

	.nfw-header,
	.nfw-footer,
	.nfw-skip {
		display: none;
	}

	/* A printed link's destination is lost unless it is written out. */
	.nfw-content a[href^="http"]::after {
		content: " (" attr(href) ")";
		font-size: 0.85em;
		word-break: break-all;
	}
}
