﻿/* ============================================================================
   MaximST — design tokens and base styles
   Grounded in Apple's Human Interface Guidelines (foundations only; this is a
   website, not an app, so platform conventions like tab bars don't apply).

   Contrast ratios in comments are measured WCAG 2.1 values, not estimates.
   ========================================================================= */

/* ---------------------------------------------------------------- TOKENS -- */

:root {
    color-scheme: light dark;

    /* -- Typography --------------------------------------------------------
       Sizes follow the HIG "Large (default)" Dynamic Type table
       (typography.md > Specifications). Apple's body is 17pt, so 17px is the
       body size here rather than the web-habitual 16px.
       Display sizes above Large Title are my own: the HIG table governs UI
       text, not marketing display type. They scale fluidly with clamp(). */
    --font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
                 "Segoe UI", Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;

    --text-caption2: 0.6875rem; /* 11px — HIG minimum for iOS */
    --text-caption1: 0.75rem;   /* 12px */
    --text-footnote: 0.8125rem; /* 13px */
    --text-subhead: 0.9375rem;  /* 15px */
    --text-callout: 1rem;       /* 16px */
    --text-body: 1.0625rem;     /* 17px — HIG default */
    --text-title3: 1.25rem;     /* 20px */
    --text-title2: 1.375rem;    /* 22px */
    --text-title1: 1.75rem;     /* 28px */
    --text-largetitle: 2.125rem;/* 34px */
    --text-display: clamp(2.5rem, 1.6rem + 4.5vw, 4.5rem);
    --text-display-lg: clamp(3rem, 1.8rem + 6vw, 6rem);

    /* Leading, from the HIG size/leading pairs: body 17/22, large title 34/41. */
    --leading-body: 1.47;
    --leading-title: 1.18;
    --leading-display: 1.05;

    /* Apple tightens tracking as size grows. */
    --tracking-display: -0.025em;
    --tracking-title: -0.015em;
    --tracking-body: 0;
    --tracking-caps: 0.06em;

    /* -- Spacing: 8pt grid ------------------------------------------------ */
    --space-1: 0.25rem;  /*  4px */
    --space-2: 0.5rem;   /*  8px */
    --space-3: 0.75rem;  /* 12px */
    --space-4: 1rem;     /* 16px */
    --space-6: 1.5rem;   /* 24px */
    --space-8: 2rem;     /* 32px */
    --space-12: 3rem;    /* 48px */
    --space-16: 4rem;    /* 64px */
    --space-24: 6rem;    /* 96px */
    --space-32: 8rem;    /* 128px */

    /* -- Radius ------------------------------------------------------------
       Apple uses continuous ("squircle") corners; CSS can't cheaply do that,
       so these are generous rounded approximations. 980px is the pill radius
       Apple uses on its own marketing buttons. */
    --radius-control: 0.625rem; /* 10px */
    --radius-card: 1.125rem;    /* 18px */
    --radius-pill: 980px;

    /* -- Layout ------------------------------------------------------------ */
    --content-width: 68rem;
    --reading-width: 38rem; /* ~70 characters at body size */
    --nav-height: 3rem;

    /* -- Motion ------------------------------------------------------------
       motion.md > Best practices: "Add motion purposefully" and "Make motion
       optional". Durations stay short; reduced-motion zeroes them out below. */
    --duration-fast: 150ms;
    --duration-base: 300ms;
    --duration-slow: 500ms;
    --ease-out: cubic-bezier(0.28, 0.11, 0.32, 1);
    --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);

    --z-nav: 100;
}

/* -- Color: light (default) ------------------------------------------------
   Semantic names by role, never by appearance (color.md > System colors:
   "Each dynamic color is semantically defined by its purpose").
   Accent is a deepened form of the site's original brand #445c7a, which at
   6.87:1 on white sat just under the 7:1 that dark-mode.md recommends for
   custom colors — and only reached 3.06:1 on black, failing dark mode
   outright. Hence a distinct variant per appearance. */
:root {
    --surface: #ffffff;
    --surface-secondary: #f5f5f7;
    --surface-raised: #ffffff;

    --content: #1d1d1f;           /* 16.83:1 on surface */
    --content-secondary: #6e6e73; /*  5.07:1 on surface, 4.66:1 on surface-secondary */
    --content-tertiary: #86868b;  /*  3.62:1 — only for >=18px or bold text */

    --accent: #3d5470;            /*  7.78:1 on surface */
    --on-accent: #ffffff;         /*  7.78:1 on accent */

    --hairline: #d2d2d7;
    --material: rgba(255, 255, 255, 0.72);
    --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.04), 0 8px 24px rgba(0, 0, 0, 0.06);
}

/* -- Color: dark -----------------------------------------------------------
   dark-mode.md > Best practices: "Avoid offering an app-specific appearance
   setting." So this follows the system and there is deliberately no toggle.
   Dark surfaces use Apple's base/elevated idea: base recedes, raised advances. */
@media (prefers-color-scheme: dark) {
    :root {
        --surface: #000000;
        --surface-secondary: #1c1c1e;
        --surface-raised: #1c1c1e;

        --content: #f5f5f7;           /* 19.29:1 on surface */
        --content-secondary: #98989d; /*  7.31:1 on surface, 5.93:1 on surface-secondary */
        --content-tertiary: #8e8e93;

        --accent: #8aa8cc;            /*  8.55:1 on surface, 6.93:1 on surface-secondary */
        --on-accent: #000000;         /*  8.55:1 on accent */

        --hairline: #38383a;
        --material: rgba(22, 22, 24, 0.72);
        --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.5), 0 8px 24px rgba(0, 0, 0, 0.4);
    }
}

/* -- Increased contrast ----------------------------------------------------
   color.md: "If you define a custom color... supply an increased contrast
   option for each variant that provides a significantly higher amount of
   visual differentiation." */
@media (prefers-contrast: more) {
    :root {
        --content-secondary: #4b4b50;
        --content-tertiary: #4b4b50;
        --accent: #2f4a63; /* 9.21:1 on white */
        --hairline: #6e6e73;
    }

    @media (prefers-color-scheme: dark) {
        :root {
            --content-secondary: #d0d0d4;
            --content-tertiary: #d0d0d4;
            --accent: #a0bade; /* 10.57:1 on black */
            --hairline: #8e8e93;
        }
    }
}

/* ------------------------------------------------------------------ BASE -- */

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

html {
    /* Native smooth anchor scrolling — replaces the old scrollto.js interop. */
    scroll-behavior: smooth;
    scroll-padding-top: calc(var(--nav-height) + var(--space-4));
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    background: var(--surface);
    color: var(--content);
    font-family: var(--font-sans);
    font-size: var(--text-body);
    line-height: var(--leading-body);
    letter-spacing: var(--tracking-body);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
    margin: 0;
    line-height: var(--leading-title);
    letter-spacing: var(--tracking-title);
    font-weight: 600;
    text-wrap: balance;
}

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

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

a {
    color: var(--accent);
    text-decoration-thickness: 1px;
    text-underline-offset: 0.2em;
}

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

address {
    font-style: normal;
}

/* Keyboard focus must stay visible — accessibility.md > Speech: "Let people
   use the keyboard alone to navigate and interact with your app." */
:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 3px;
    border-radius: var(--space-1);
}

::selection {
    background: var(--accent);
    color: var(--on-accent);
}

/* --------------------------------------------------------------- MOTION -- */

@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;
    }
}

/* ------------------------------------------------------------ PRIMITIVES -- */

.container {
    width: 100%;
    max-width: var(--content-width);
    margin-inline: auto;
    /* Respects the notch/home indicator when installed or viewed full-bleed. */
    padding-inline: max(var(--space-6), env(safe-area-inset-left));
}

.section {
    padding-block: clamp(var(--space-16), 10vw, var(--space-32));
}

.prose {
    max-width: var(--reading-width);
}

/* Visible to screen readers only. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* Skip link — first tab stop, per keyboard-only navigation. */
.skip-link {
    position: absolute;
    top: var(--space-2);
    left: var(--space-2);
    z-index: calc(var(--z-nav) + 1);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-control);
    background: var(--surface-raised);
    color: var(--content);
    box-shadow: var(--shadow-card);
    transform: translateY(-200%);
    transition: transform var(--duration-fast) var(--ease-out);
}

.skip-link:focus-visible {
    transform: translateY(0);
}

/* -------------------------------------------------------------- MATERIAL --
   materials.md: the translucent material belongs to the functional layer
   (navigation) and never to the content layer. Only the nav gets this; cards
   stay opaque. That restraint is what keeps it from reading as generic
   glassmorphism. */
.material {
    background: var(--material);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    backdrop-filter: saturate(180%) blur(20px);
}

@media (prefers-reduced-transparency: reduce) {
    .material {
        background: var(--surface);
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }
}

/* Older engines without backdrop-filter get an opaque bar rather than
   unreadable text over content. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .material {
        background: var(--surface);
    }
}

/* ------------------------------------------------------------------ TYPE -- */

.t-display {
    font-size: var(--text-display);
    line-height: var(--leading-display);
    letter-spacing: var(--tracking-display);
    font-weight: 600;
}

.t-display-lg {
    font-size: var(--text-display-lg);
    line-height: var(--leading-display);
    letter-spacing: var(--tracking-display);
    font-weight: 600;
}

.t-title1 { font-size: var(--text-title1); }
.t-title2 { font-size: var(--text-title2); }
.t-title3 { font-size: var(--text-title3); }

.t-lead {
    font-size: var(--text-title3);
    line-height: 1.4;
    letter-spacing: -0.01em;
    color: var(--content-secondary);
    font-weight: 400;
}

.t-secondary {
    color: var(--content-secondary);
}

/* Small caps label. Letter-spaced, and never below the 11px HIG minimum. */
.t-eyebrow {
    font-size: var(--text-caption1);
    line-height: 1.3;
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    font-weight: 600;
    color: var(--content-secondary);
}

/* ============================================================================
   COMPONENTS
   ========================================================================= */

/* ------------------------------------------------------------------- NAV -- */

.nav {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: var(--z-nav);
    height: var(--nav-height);
    border-bottom: 1px solid var(--hairline);
    padding-top: env(safe-area-inset-top);
}

.nav-inner {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    height: var(--nav-height);
}

.nav-brand {
    font-size: var(--text-subhead);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--content);
    text-decoration: none;
    margin-right: auto;
}

.nav-links {
    display: flex;
    align-items: center;
    gap: var(--space-1);
}

/* Full nav height keeps the tap target at 48px, above the 44pt HIG default. */
.nav-link,
.lang-toggle {
    display: inline-flex;
    align-items: center;
    height: var(--nav-height);
    padding-inline: var(--space-3);
    font-size: var(--text-footnote);
    color: var(--content-secondary);
    text-decoration: none;
    transition: color var(--duration-fast) var(--ease-out);
}

.nav-link:hover,
.lang-toggle:hover {
    color: var(--content);
}

.nav-link:active,
.lang-toggle:active,
.contact-mail:active,
.footer a:active {
    opacity: 0.6;
}

.lang-toggle {
    margin-left: var(--space-2);
    padding-inline: var(--space-3);
    border-left: 1px solid var(--hairline);
    font-variant-caps: all-small-caps;
    letter-spacing: var(--tracking-caps);
}

/* Section links are secondary to the language switch on a narrow screen. */
@media (max-width: 30rem) {
    .nav-links {
        display: none;
    }
}

/* ------------------------------------------------------------------ HERO -- */

.hero {
    display: flex;
    align-items: center;
    min-height: min(88svh, 50rem);
    padding-top: calc(var(--nav-height) + var(--space-16));
    padding-bottom: var(--space-16);
}

.hero-title {
    max-width: 16ch;
    margin-bottom: var(--space-8);
}

.hero-sub {
    max-width: var(--reading-width);
    margin-bottom: var(--space-12);
}

.hero-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3) var(--space-6);
}

/* --------------------------------------------------------------- BUTTONS -- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: 2.75rem; /* 44px — HIG default control size */
    padding: var(--space-3) var(--space-6);
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
    font-size: var(--text-callout);
    font-weight: 500;
    text-decoration: none;
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out),
                opacity var(--duration-fast) var(--ease-out);
}

/* color.md: "To emphasize primary actions, apply color to the background."
   Exactly one filled button exists on the page. */
.btn-primary {
    background: var(--accent);
    color: var(--on-accent);
}

.btn-primary:hover {
    opacity: 0.88;
}

.btn-primary:active {
    opacity: 0.7;
}

.btn-secondary {
    border-color: var(--hairline);
    color: var(--content);
}

.btn-secondary:hover {
    border-color: var(--content-tertiary);
}

.btn-secondary:active {
    background: var(--surface-secondary);
    border-color: var(--content-secondary);
}

/* -------------------------------------------------------------- SECTIONS -- */

.section-head {
    margin-bottom: var(--space-12);
}

.section-head .t-eyebrow {
    display: block;
    margin-bottom: var(--space-3);
}

/* -------------------------------------------------------------- EXPERTISE --
   A hairline-separated row list rather than a card grid: five cards leave an
   orphan in a three-column layout, and the row form reads as substantial
   rather than templated. */

.exp-row {
    display: grid;
    gap: var(--space-4);
    padding-block: var(--space-8);
    border-top: 1px solid var(--hairline);
}

.exp-row:last-child {
    border-bottom: 1px solid var(--hairline);
}

@media (min-width: 48rem) {
    .exp-row {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1.9fr);
        gap: var(--space-8);
        padding-block: var(--space-12);
    }
}

.exp-title {
    font-size: var(--text-title2);
    text-wrap: balance;
}

.exp-body {
    max-width: var(--reading-width);
    color: var(--content-secondary);
    margin-bottom: var(--space-6);
}

/* Tags carry over from the original site, but grouped per area they now say
   which domain each technology belongs to instead of forming one long wall. */
.tags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.tag {
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--hairline);
    border-radius: var(--radius-pill);
    font-size: var(--text-caption1);
    letter-spacing: 0.01em;
    color: var(--content-secondary);
    white-space: nowrap;
}

/* ------------------------------------------------------------- ADVISORY --
   The service the business leads with, so it gets the tinted ground directly
   under the hero. Steps are an ordered list: the order is the engagement. */

.advisory {
    background: var(--surface-secondary);
}

.advisory-intro {
    margin-top: var(--space-6);
}

.steps {
    display: grid;
    gap: var(--space-4);
    margin: 0 0 var(--space-12);
    padding: 0;
    list-style: none;
    counter-reset: step;
}

@media (min-width: 48rem) {
    .steps {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--space-6);
    }
}

.step {
    counter-increment: step;
    padding: var(--space-8);
    border-radius: var(--radius-card);
    /* In dark mode surface-raised equals surface-secondary; the hairline keeps
       the cards from dissolving into the section ground. */
    border: 1px solid var(--hairline);
    background: var(--surface-raised);
    box-shadow: var(--shadow-card);
}

.step::before {
    content: counter(step, decimal-leading-zero);
    display: block;
    margin-bottom: var(--space-4);
    font-size: var(--text-title3);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--accent);
}

.step-title {
    font-size: var(--text-title3);
    margin-bottom: var(--space-2);
}

.step-body {
    color: var(--content-secondary);
}

/* ----------------------------------------------------------------- ABOUT -- */

.about {
    background: var(--surface-secondary);
}

.about-grid {
    display: grid;
    gap: var(--space-8);
    align-items: start;
}

@media (min-width: 48rem) {
    .about-grid {
        grid-template-columns: minmax(0, 18rem) minmax(0, 1fr);
        gap: var(--space-16);
    }
}

.about-photo {
    width: 100%;
    max-width: 18rem;
    aspect-ratio: 1;
    object-fit: cover;
    border-radius: var(--radius-card);
}

.about-text {
    display: grid;
    gap: var(--space-6);
    max-width: var(--reading-width);
}

/* --------------------------------------------------------------- CONTACT -- */

.contact-mail {
    display: inline-block;
    margin-top: var(--space-8);
    font-size: var(--text-title1);
    font-weight: 600;
    letter-spacing: var(--tracking-title);
    color: var(--content);
    text-decoration-color: var(--hairline);
    text-underline-offset: 0.15em;
    transition: text-decoration-color var(--duration-fast) var(--ease-out);
}

.contact-mail:hover {
    text-decoration-color: var(--accent);
}

/* ---------------------------------------------------------------- FOOTER -- */

.footer {
    border-top: 1px solid var(--hairline);
    padding-block: var(--space-12);
    padding-bottom: max(var(--space-12), env(safe-area-inset-bottom));
    font-size: var(--text-footnote);
    color: var(--content-secondary);
}

.footer-grid {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-8) var(--space-16);
    justify-content: space-between;
}

.footer-name {
    font-weight: 600;
    color: var(--content);
}

.footer-links {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-6);
    align-items: flex-start;
}

.footer a {
    color: var(--content-secondary);
    text-decoration: none;
}

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

.footer-note {
    width: 100%;
    /* Was --content-tertiary: 3.62:1 at 12px, under the 4.5:1 floor for text
       below 18px. That token is documented as large/bold text only. */
    color: var(--content-secondary);
    font-size: var(--text-caption1);
}

/* ---------------------------------------------------------------- REVEAL --
   motion.md > Best practices: "Add motion purposefully, supporting the
   experience without overshadowing it." One short fade with a small rise, on
   section headers and expertise rows only.

   The armed (hidden) state is added by JS and never lives in the markup: if
   the script fails or never runs, content is simply visible rather than
   permanently blank. Elements already on screen at load are skipped entirely,
   so nothing fades in over the first paint. */

.reveal-armed {
    opacity: 0;
    transform: translateY(1rem);
}

.reveal-in {
    opacity: 1;
    transform: none;
    transition: opacity var(--duration-slow) var(--ease-out),
                transform var(--duration-slow) var(--ease-out);
}

/* The expertise list is two groups: the three the business leads with, then
   the supporting range. The label carries that distinction; the secondary
   rows are set slightly quieter so the hierarchy is visible, not just stated. */
.exp-group-label {
    margin-top: var(--space-16);
    margin-bottom: var(--space-6);
}

.exp-row-secondary .exp-title {
    font-size: var(--text-title3);
}

.exp-row-secondary .exp-body {
    font-size: var(--text-callout);
}
