/*
Theme Name: OryxSoft
Theme URI: https://oryxsoft.tech
Author: Nicholas Hudson
Author URI: https://oryxsoft.tech
Description: Block theme for OryxSoft, LLC. The page is dimensioned rather than laid out — two extension lines run the full height of the sheet, and a single dimension line beneath the wordmark states the company's legal identity.
Version: 1.0.0
Requires at least: 6.5
Tested up to: 6.8
Requires PHP: 8.2
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: oryxsoft
Tags: block-theme, one-column, full-site-editing, accessibility-ready
*/

/* ══════════════════════════════════════════════════════════════════════════
   Everything design-token-shaped lives in theme.json. This file holds only
   what theme.json cannot express: the extension lines, the dimension line,
   the load animation, font-stretch, and the metric-matched font fallback.
   ══════════════════════════════════════════════════════════════════════════ */

/* ─── Metric-matched fallback ────────────────────────────────────────────────
   theme.json can declare a fontFace but not a local()-sourced fallback, and
   without one the swap from Consolas to DM Mono shifts layout. These
   overrides bring the fallback's metrics onto DM Mono's so CLS stays at 0. */

@font-face {
  font-family: "DM Mono Fallback";
  src: local("Consolas"), local("Menlo"), local("DejaVu Sans Mono"), local("monospace");
  size-adjust: 96%;
  ascent-override: 92%;
  descent-override: 24%;
  line-gap-override: 0%;
}

/* ─── Local aliases ─────────────────────────────────────────────────────── */

:root {
  --ox-sheet: var(--wp--custom--sheet-inset);
  --ox-ext: var(--wp--custom--ext-inset);
  --ox-rule: var(--wp--preset--color--rule);
  --ox-redline: var(--wp--preset--color--redline);

  /* Half the content measure (960px), used to find the container edge. */
  --ox-half: 480px;

  /* Distance from the viewport edge to an extension line. Below the content
     measure this is just the inset; above it, the lines track the centred
     column rather than drifting out to the window edges. Shared by the lines
     themselves and by anything that has to terminate on them. */
  --ox-edge: max(var(--ox-ext), calc(50% - var(--ox-half) - var(--ox-sheet) + var(--ox-ext)));
}

/* ═══ THE SIGNATURE ════════════════════════════════════════════════════════
   An oryx's two straight horns read as the extension lines of a dimension
   callout. These run the full height of the document and simultaneously act
   as the horns, the dimension geometry, and the layout gutters.

   Positioned against the *content* edge rather than the viewport, so they
   stay locked to the text column past the 960px measure.
   ═══════════════════════════════════════════════════════════════════════ */

body {
  position: relative;
}

body::before,
body::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--ox-rule);
  pointer-events: none;
  z-index: 0;
  transform: scaleY(0);
  transform-origin: top;
  animation: ox-draw-down 420ms cubic-bezier(0.4, 0, 0.1, 1) forwards;
}

body::before { left: var(--ox-edge); }
body::after { right: var(--ox-edge); }

@keyframes ox-draw-down {
  to { transform: scaleY(1); }
}

/* Keep real content above the lines, and let the footer fall to the bottom
   of the viewport on short pages (404) without floating on tall ones. */
.wp-site-blocks {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* ─── The dimension line ─────────────────────────────────────────────────── */

.ox-dim {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  /* Break out of the content measure to meet the extension lines. */
  margin-inline: calc(var(--ox-ext) - var(--ox-sheet));
  margin-block: clamp(1.5rem, 4vw, 2.25rem) 0;
}

.ox-dim__line {
  flex: 1 1 auto;
  min-width: 10px;
  height: 1px;
  background: var(--ox-redline);
  transform: scaleX(0);
  animation: ox-draw-out 360ms cubic-bezier(0.4, 0, 0.1, 1) 300ms forwards;
}

.ox-dim__line--l { transform-origin: right; }
.ox-dim__line--r { transform-origin: left; }

@keyframes ox-draw-out {
  to { transform: scaleX(1); }
}

.ox-dim__arrow {
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  color: var(--ox-redline);
  opacity: 0;
  animation: ox-land 160ms ease-out 660ms forwards;
}

.ox-dim__arrow--l { margin-right: -0.75rem; }
.ox-dim__arrow--r { margin-left: -0.75rem; }

@keyframes ox-land {
  to { opacity: 1; }
}

.ox-dim__value {
  flex: 0 0 auto;
  font-size: var(--wp--preset--font-size--annotation);
  line-height: 1;
  letter-spacing: var(--wp--custom--tracking--wide);
  text-transform: uppercase;
  color: var(--ox-redline);
  white-space: nowrap;
}

/* ─── One orchestrated moment, or none ───────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  body::before,
  body::after,
  .ox-dim__line,
  .ox-dim__arrow {
    animation: none;
    transform: none;
    opacity: 1;
  }
}

/* ═══ Type ════════════════════════════════════════════════════════════════
   font-stretch is not a theme.json style property, so the width axis has to
   be driven from here. The display face is only ever 700; width does the
   differentiating.
   ═══════════════════════════════════════════════════════════════════════ */

h1, h2,
.wp-block-site-title,
.ox-wordmark {
  font-stretch: var(--wp--custom--stretch--display);
}

h3, h4, h5, h6 {
  font-stretch: var(--wp--custom--stretch--name);
}

/* The wordmark. Sized against Archivo's real advance width at wdth 125%
   (5.16 x font-size at -0.03em) so it fills the measure at desktop and
   never overflows at 320px. Not animated — it is the LCP element. */

h1.ox-wordmark {
  font-family: var(--wp--preset--font-family--display);
  font-weight: 700;
  font-size: var(--wp--preset--font-size--wordmark);
  line-height: 0.9;
  letter-spacing: var(--wp--custom--tracking--tight);
  text-transform: none;
  margin: 0;
}

.ox-lede {
  max-width: var(--wp--custom--measure);
  font-size: var(--wp--preset--font-size--lede);
  line-height: 1.6;
}

.ox-annotation {
  font-size: var(--wp--preset--font-size--annotation);
  text-transform: uppercase;
  letter-spacing: var(--wp--custom--tracking--wide);
  color: var(--wp--preset--color--annotation);
}

/* ═══ Header ══════════════════════════════════════════════════════════════ */

.ox-masthead {
  padding-block: 1.75rem 0;
}

.ox-nav a,
.wp-block-navigation .wp-block-navigation-item__content {
  font-size: var(--wp--preset--font-size--annotation);
  text-transform: uppercase;
  letter-spacing: var(--wp--custom--tracking--wide);
  color: var(--wp--preset--color--annotation);
  border-bottom: 1px solid transparent;
  padding-bottom: 2px;
}

.ox-nav a:hover,
.wp-block-navigation .wp-block-navigation-item__content:hover {
  color: var(--wp--preset--color--graphite);
  border-bottom-color: var(--ox-redline);
}

/* ═══ Product ledger ══════════════════════════════════════════════════════
   Rows, not cards. A card grid with one product looks broken; a ledger with
   one row looks deliberate, and so does one with four.
   ═══════════════════════════════════════════════════════════════════════ */

.ox-ledger {
  border-top: 1px solid var(--ox-rule);
  /* Bleed out to the extension lines... */
  margin-inline: calc(var(--ox-ext) - var(--ox-sheet));
}

.ox-product {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem 2rem;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--ox-rule);
  background: var(--wp--preset--color--sheet);
  padding-block: var(--wp--preset--spacing--30);
  /* ...then pad the contents back onto the content grid. */
  padding-inline: calc(var(--ox-sheet) - var(--ox-ext));
}

/* Product names are h3 on the home page (under the "Products" heading) and h2
   on the Products page (under the page title). h2 otherwise carries the
   uppercase title-block treatment, so the name role has to override it in
   both cases rather than inherit whichever level it happens to sit at. */
h2.ox-product__name,
h3.ox-product__name {
  font-size: var(--wp--preset--font-size--name);
  font-stretch: var(--wp--custom--stretch--name);
  text-transform: none;
  letter-spacing: -0.01em;
  line-height: 1.1;
  margin: 0 0 0.5rem;
}

.ox-product__what {
  margin: 0;
  color: var(--wp--preset--color--annotation);
  max-width: 46ch;
}

.ox-product__go {
  font-size: var(--wp--preset--font-size--annotation);
  text-transform: uppercase;
  letter-spacing: var(--wp--custom--tracking--wide);
  white-space: nowrap;
  border-bottom: 1px solid var(--ox-rule);
  padding-bottom: 3px;
}

.ox-product__go:hover {
  border-bottom-color: var(--ox-redline);
}

/* ═══ Contact ═════════════════════════════════════════════════════════════ */

.ox-contact__who {
  font-size: var(--wp--preset--font-size--name);
  margin: var(--wp--preset--spacing--20) 0 0.25rem;
}

.ox-mail {
  display: inline-block;
  font-size: var(--wp--preset--font-size--lede);
  border-bottom: 1px solid var(--ox-rule);
  padding-bottom: 3px;
}

.ox-mail:hover {
  border-bottom-color: var(--ox-redline);
}

/* ═══ Footer ══════════════════════════════════════════════════════════════ */

/* The footer wrapper runs the full viewport width, so its rule has to be drawn
   rather than declared — a border-top would span the window instead of
   terminating on the extension lines. */
.ox-colophon {
  position: relative;
  /* The gap above the footer is padding, not margin, so margin-top:auto is
     free to push it to the bottom on short pages. */
  padding-block: clamp(3rem, 8vh, 5rem) 2.5rem;
  margin-top: auto;
}

.ox-colophon::before {
  content: "";
  position: absolute;
  top: 0;
  left: var(--ox-edge);
  right: var(--ox-edge);
  height: 1px;
  background: var(--ox-rule);
}

/* Keep the last section off the footer rule. */
.wp-site-blocks > main {
  padding-bottom: var(--wp--preset--spacing--50);
}

.ox-colophon a {
  border-bottom: 1px solid transparent;
}

.ox-colophon a:hover {
  border-bottom-color: var(--ox-redline);
}

/* ═══ Focus ═══════════════════════════════════════════════════════════════
   Redline earns its place on exactly three things: the dimension, link
   hover, and this. The moment it appears on a button it stops meaning
   anything.
   ═══════════════════════════════════════════════════════════════════════ */

:focus-visible {
  outline: 2px solid var(--ox-redline);
  outline-offset: 3px;
}

/* Skip link — visible the moment it takes focus. */
.skip-link:focus {
  background: var(--wp--preset--color--film);
  color: var(--wp--preset--color--graphite);
  outline: 2px solid var(--ox-redline);
  outline-offset: 3px;
  padding: 0.75rem 1rem;
  z-index: 100;
}

/* ═══ Narrow ══════════════════════════════════════════════════════════════ */

@media (max-width: 420px) {
  .ox-dim { gap: 0.5rem; }
  .ox-dim__value {
    font-size: 0.6875rem;
    letter-spacing: 0.06em;
  }
  .ox-dim__arrow--l { margin-right: -0.5rem; }
  .ox-dim__arrow--r { margin-left: -0.5rem; }
}
