/* ==========================================================================
   WSIDO — Apple-design pass
   Layered over the compiled Tailwind sheet. Loaded after it in <head>.
   Section numbers refer to the apple-design skill.
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. MOTION SAFETY — §3 (interruptibility) / §14 (reduced motion)
   The SSR'd HTML ships 56 elements at opacity:0 (framer-motion initial state).
   Without JS, or with reduced motion requested, the page must still read.
   -------------------------------------------------------------------------- */

/* Two failure paths, one outcome — content is readable either way:
   .js absent      -> scripting is off, nothing will ever animate these in.
   .no-reveal set  -> the bundle loaded but never hydrated (guard in <head>).
   Covers the h1 and p that carry the inline state directly, not just the
   Reveal wrapper divs. */
html:not(.js) [style*="opacity:0"],
html.no-reveal [style*="opacity:0"] {
  opacity: 1 !important;
  transform: none !important;
}

@media (prefers-reduced-motion: reduce) {
  /* !important beats framer-motion's inline style, so content stays put. */
  main [style],
  header [style],
  footer [style] {
    opacity: 1 !important;
    transform: none !important;
  }

  /* §14: gentler equivalent, not "no feedback". Keep short cross-fades,
     drop travel and overshoot. */
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 150ms !important;
    transition-timing-function: ease !important;
  }
  html { scroll-behavior: auto !important; }
}

/* --------------------------------------------------------------------------
   1. TYPOGRAPHY — §15
   Tracking is size-specific. The build applies tracking-tightest (-0.05em)
   to both the 72px h1 and the 30px section h2s; that value is a display
   setting and is too tight below ~40px. Leading is re-paired to each size.
   -------------------------------------------------------------------------- */

html { font-optical-sizing: auto; }

/* Display — h1. Negative tracking earns its place at this size. */
main h1 {
  letter-spacing: -0.042em;
  line-height: 1.03;
}
@media (max-width: 639px) {
  main h1 { letter-spacing: -0.03em; line-height: 1.08; }
}

/* Section headings — looser than the h1, still tight. */
main h2 {
  letter-spacing: -0.028em;
  line-height: 1.08;
}
@media (min-width: 768px) {
  main h2 { letter-spacing: -0.034em; }
}

/* The RugbyIntel wordmark-scale h2 sits larger than the rest; keep it tighter. */
#rugbyintel h2 { letter-spacing: -0.038em; }

/* Card / sub headings — barely tightened, never display tracking. */
main h3 { letter-spacing: -0.012em; line-height: 1.25; }

/* Body copy sits at 0 tracking. §15: only large text wants negative. */
main p, footer p {
  letter-spacing: 0;
  font-feature-settings: "ss01", "cv01", "cv11", "kern";
}

/* Small uppercase eyebrows already carry +0.05em via tracking-wider — correct.
   Nudge weight instead of spacing so they hold presence at 12px (§15). */
main span.uppercase, footer h3.uppercase {
  font-weight: 500;
}

/* Data should not shift width as it updates (§16 craft). */
#rugbyintel .rounded-2xl,
#rugbyintel dl {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum", "ss01";
}

/* --------------------------------------------------------------------------
   2. LEGIBILITY — §12 (vibrancy) / §16 (craft)
   muted-foreground/60 measured 3.18:1 and /70 measured 3.95:1 against the
   #080A0C background — both under the 4.5:1 the site claims to meet.
   /82 lands near 5.0:1 and is visually almost identical.
   -------------------------------------------------------------------------- */

.text-muted-foreground\/60,
.text-muted-foreground\/70 {
  color: hsl(var(--muted-foreground) / 0.82);
}

/* §12: text over a translucent surface wants a touch more weight, not flat grey. */
header nav a { font-weight: 500; }

/* --------------------------------------------------------------------------
   3. MOTION FEEL — §1 (respond on pointer-down) / §4 (critically damped)
   Every CSS-driven transition gets a damping-1.0 curve and a response in
   the 0.2–0.4s band. No overshoot anywhere: none of these are momentum
   interactions, and bounce on a hover reads as cheap (§4).
   -------------------------------------------------------------------------- */

:root {
  --ease-damped: cubic-bezier(0.32, 0.72, 0, 1); /* critically damped, no bounce */
  --response-fast: 0.2s;
  --response-base: 0.34s;
}

a, button,
.transition-colors,
.transition-transform,
[class*="transition-"] {
  transition-timing-function: var(--ease-damped);
}

/* §1: feedback lives on the press and is instant — never on release. */
a:active,
button:active {
  transform: scale(0.97);
  transition: transform 100ms ease-out;
}

/* Large surfaces compress less; a card shrinking 3% looks broken. */
a.rounded-2xl:active,
a[class*="flex-col"]:active,
#rugbyintel a:active {
  transform: scale(0.994);
}

/* §16 craft: the focus ring is a designed state, not a browser default.
   The --ring token already ships in the build and was never used. */
a:focus-visible,
button:focus-visible {
  outline: 2px solid hsl(var(--ring) / 0.9);
  outline-offset: 3px;
  border-radius: 8px;
  transition: none; /* focus must appear instantly */
}

/* --------------------------------------------------------------------------
   4. MATERIALS — §12
   The nav already blurs on scroll. These give it saturation, a light-catching
   edge, and a scroll-edge fade in place of the 1px divider.
   -------------------------------------------------------------------------- */

header.fixed {
  transition: background-color var(--response-base) var(--ease-damped),
              backdrop-filter var(--response-base) var(--ease-damped);
}

/* JS adds backdrop-blur-xl past 8px of scroll — that class is the scrolled state. */
header.backdrop-blur-xl {
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  backdrop-filter: blur(24px) saturate(180%);
  border-bottom-color: transparent !important; /* replaced by the fade below */
}

/* Light catching the top of the material (§12). */
header.backdrop-blur-xl::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: linear-gradient(
    90deg,
    transparent,
    hsl(var(--foreground) / 0.12) 20%,
    hsl(var(--foreground) / 0.12) 80%,
    transparent
  );
  pointer-events: none;
}

/* §12: scroll edge effect, not a hard divider. The content fades under the
   chrome instead of being cut by a line. */
header.backdrop-blur-xl::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: 28px;
  background: linear-gradient(
    to bottom,
    hsl(var(--background) / 0.55),
    hsl(var(--background) / 0)
  );
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  -webkit-mask-image: linear-gradient(to bottom, #000, transparent);
  mask-image: linear-gradient(to bottom, #000, transparent);
  pointer-events: none;
}

/* Mobile sheet — §12 "materialize, don't just fade": blur and scale arrive
   together so it reads as a real surface, not an opacity ramp. */
header .md\:hidden.backdrop-blur-xl,
header div.backdrop-blur-xl {
  -webkit-backdrop-filter: blur(28px) saturate(180%);
  backdrop-filter: blur(28px) saturate(180%);
}

/* --------------------------------------------------------------------------
   5. DEPTH & HIERARCHY — §12
   Material weight encodes rank. Bigger surfaces read thicker: deeper shadow,
   stronger edge. Small chips stay nearly flat so they don't compete.
   -------------------------------------------------------------------------- */

/* Every card gets a top inset hairline — light landing on a raised edge. */
.bg-card {
  box-shadow: inset 0 1px 0 hsl(var(--foreground) / 0.055);
}

/* Flush tiles in the gap-px grids. These share 1px seams, so a lift would
   tear the grid — they brighten in place instead (§16 restraint). */
.gap-px .bg-card {
  transition: background-color var(--response-base) var(--ease-damped),
              box-shadow var(--response-base) var(--ease-damped);
}
.gap-px .bg-card:hover {
  box-shadow: inset 0 1px 0 hsl(var(--foreground) / 0.1);
}

/* Standalone cards can lift. Compositor-only properties (§11). */
a.rounded-2xl.bg-card,
.rounded-2xl.bg-card {
  box-shadow:
    inset 0 1px 0 hsl(var(--foreground) / 0.06),
    0 1px 2px hsl(0 0% 0% / 0.5),
    0 8px 24px -8px hsl(0 0% 0% / 0.45);
  transition: transform var(--response-base) var(--ease-damped),
              box-shadow var(--response-base) var(--ease-damped),
              background-color var(--response-base) var(--ease-damped);
  will-change: transform;
}
a.rounded-2xl.bg-card:hover {
  transform: translateY(-2px);
  box-shadow:
    inset 0 1px 0 hsl(var(--foreground) / 0.09),
    0 2px 4px hsl(0 0% 0% / 0.5),
    0 18px 44px -12px hsl(0 0% 0% / 0.6);
}

/* The RugbyIntel panel is the largest surface on the page — thickest material. */
#rugbyintel .rounded-2xl.bg-card {
  box-shadow:
    inset 0 1px 0 hsl(var(--foreground) / 0.08),
    0 2px 6px hsl(0 0% 0% / 0.5),
    0 32px 64px -20px hsl(0 0% 0% / 0.7);
}

/* Small stat chips stay nearly flat — §12, light materials don't stack. */
.rounded-xl.bg-card {
  box-shadow: inset 0 1px 0 hsl(var(--foreground) / 0.05);
}

/* --------------------------------------------------------------------------
   6. HERO SURFACE — §11 (frame quality) / §16 (craft)
   A 60%-wide radial gradient over near-black banks visibly on 8-bit panels.
   A trace of grain breaks the bands without reading as texture.
   -------------------------------------------------------------------------- */

div[aria-hidden="true"][class*="-z-10"] {
  position: absolute;
}
div[aria-hidden="true"][class*="-z-10"]::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.011;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* --------------------------------------------------------------------------
   7. ACCESSIBILITY PREFERENCES — §14
   Translucency and contrast are user settings, not fixed design choices.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-transparency: reduce) {
  header.backdrop-blur-xl,
  header div.backdrop-blur-xl {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    background-color: hsl(var(--background));
  }
  header.backdrop-blur-xl::after { display: none; }
  header.backdrop-blur-xl { border-bottom-color: hsl(var(--border)) !important; }
}

@media (prefers-contrast: more) {
  header.backdrop-blur-xl,
  header div.backdrop-blur-xl {
    background-color: hsl(var(--background));
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .bg-card { border-color: hsl(var(--foreground) / 0.35); }
  .text-muted-foreground\/60,
  .text-muted-foreground\/70,
  .text-muted-foreground\/80,
  .text-muted-foreground {
    color: hsl(var(--foreground));
  }
}

/* --------------------------------------------------------------------------
   8. CONTACT PAGE
   Two utilities the compiled Tailwind sheet does not ship (the source build
   never used them), expressed directly instead.
   -------------------------------------------------------------------------- */

main address { font-style: normal; }

/* §7: the back arrow points the way it travels. */
.arrow-back { transition: transform var(--response-fast) var(--ease-damped); }
.group:hover .arrow-back { transform: translateX(-2px); }

/* Four contact cards read best as one row on desktop; the compiled sheet
   ships no grid-cols-4, so it is declared here. */
@media (min-width: 1024px) {
  .contact-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* --------------------------------------------------------------------------
   9. ARTICLE BODY — §15
   Long-form prose wants looser leading than UI text and a measure that stops
   the eye getting lost. Tracking stays at 0: this is body copy, not display.
   -------------------------------------------------------------------------- */

.article-body {
  font-size: 1.0625rem;
  line-height: 1.75;
  letter-spacing: 0;
  color: hsl(var(--muted-foreground) / 0.95);
}

.article-body > * + * { margin-top: 1.4em; }

.article-body h2 {
  margin-top: 2.6em;
  margin-bottom: -0.35em;
  font-size: 1.5rem;
  line-height: 1.2;
  letter-spacing: -0.022em;   /* §15: tighten as size grows, but not display-tight */
  font-weight: 600;
  color: hsl(var(--foreground));
  text-wrap: balance;
}

.article-body h3 {
  margin-top: 2em;
  margin-bottom: -0.45em;
  font-size: 1.125rem;
  line-height: 1.3;
  letter-spacing: -0.012em;
  font-weight: 600;
  color: hsl(var(--foreground));
}

.article-body strong { color: hsl(var(--foreground)); font-weight: 600; }
.article-body em { color: hsl(var(--foreground) / 0.9); }

.article-body ul { padding-left: 1.15em; list-style: none; }
.article-body li { position: relative; margin-top: 0.7em; }
.article-body li::before {
  content: "";
  position: absolute;
  left: -1.05em;
  top: 0.72em;
  width: 4px;
  height: 4px;
  border-radius: 9999px;
  background: hsl(var(--muted-foreground) / 0.55);
}

/* A comfortable measure regardless of container width (§15). */
.article-body p, .article-body li { max-width: 68ch; }

@media (min-width: 768px) {
  .article-body { font-size: 1.125rem; }
  .article-body h2 { font-size: 1.75rem; letter-spacing: -0.026em; }
}

/* A capability tile may span the rest of its row, so the grid closes cleanly
   instead of leaving a void. Column counts track the grid's own breakpoints
   (2 / sm:3 / lg:5). */
.tech-wide { grid-column: span 2 / span 2; }
@media (min-width: 1024px) {
  .tech-wide { grid-column: span 5 / span 5; }
}
