/* ============================================================
   O'Gabbie Design Studio — site.css
   Shared token layer, shell and components.
   Dark is default (brand primary). Light is switchable.
   ============================================================ */

/* ---------- 1. TOKENS ---------------------------------------- */

:root {
  /* Dark, the brand's primary mode */
  --ground:          #0B0A09;
  --ground-alt:      #141210;
  --surface:         #141210;
  --surface-raised:  #262320;
  --panel:           #1D1B18;
  --on-panel:        #EDE8E2;

  --text:            #EDE8E2;
  --text-2:          #B4ADA6;
  --muted:           #726C66;

  --accent:          #B8935A;
  --accent-2:        #8BAABB;
  --accent-dim:      rgba(184, 147, 90, 0.10);
  --accent-border:   rgba(184, 147, 90, 0.28);

  --border:          rgba(255, 255, 255, 0.06);
  --border-strong:   rgba(255, 255, 255, 0.12);
  --ok:              #4DAF84;

  /* Panel needs a visible edge in dark mode, where it lifts rather than drops */
  --panel-ring:      var(--accent-border);
  --panel-glow:      radial-gradient(120% 90% at 50% 40%, rgba(184,147,90,0.13), transparent 70%);

  /* macOS window chrome. Deliberately literal in both modes. */
  --chrome-red:      #EC6A5E;
  --chrome-yellow:   #F5BF4F;
  --chrome-green:    #61C554;

  /* Type */
  --font-display: 'Inter', system-ui, -apple-system, sans-serif;
  --font-body:    'Inter', system-ui, -apple-system, sans-serif;
  --font-mono:    'IBM Plex Mono', ui-monospace, 'SFMono-Regular', monospace;

  /* Spacing tiers. Variable rhythm, never uniform. */
  /* Trimmed 2026-09-12. The editorial rhythm was leaving roughly 340px of dead
     ground between a stats block and the next heading, which read as a missing
     section rather than as air. Consecutive panels were worse, because two
     paddings meet with nothing between them. */
  --pad-tight:     56px;
  --pad-default:   92px;
  --pad-editorial:124px;
  --gutter:        40px;

  --rail-w:       472px;
  --split-gap:     24px;
  --measure:      864px;

  --ease:      cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out:  cubic-bezier(0.33, 1, 0.68, 1);
  --theme-t:   240ms;
}

:root[data-theme="light"] {
  --ground:          #F2EDE6;
  --ground-alt:      #EDE7DE;
  --surface:         #FDFAF6;
  --surface-raised:  #EDE7DE;
  --panel:           #0B0A09;
  --on-panel:        #EDE8E2;

  --text:            #1A1714;
  --text-2:          #4A4540;
  --muted:           #8A8278;

  --accent:          #9E7A3A;
  --accent-2:        #4E6E82;
  --accent-dim:      rgba(158, 122, 58, 0.10);
  --accent-border:   rgba(158, 122, 58, 0.28);

  --border:          rgba(0, 0, 0, 0.08);
  --border-strong:   rgba(0, 0, 0, 0.16);
  --ok:              #2E7D55;

  /* In light mode the panel is already a dramatic drop. No ring, no glow. */
  --panel-ring:      transparent;
  --panel-glow:      none;
}

/* No-JS fallback only. The head script sets data-theme explicitly, so this
   never fights the toggle. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]):not([data-theme="light"]) {
    --ground: #F2EDE6; --ground-alt: #EDE7DE; --surface: #FDFAF6;
    --surface-raised: #EDE7DE; --panel: #0B0A09;
    --text: #1A1714; --text-2: #4A4540; --muted: #8A8278;
    --accent: #9E7A3A; --accent-2: #4E6E82;
    --accent-dim: rgba(158,122,58,0.10); --accent-border: rgba(158,122,58,0.28);
    --border: rgba(0,0,0,0.08); --border-strong: rgba(0,0,0,0.16); --ok: #2E7D55;
    --panel-ring: transparent; --panel-glow: none;
  }
}

/* ---------- 2. RESET ----------------------------------------- */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-variant-numeric: lining-nums tabular-nums;
  text-size-adjust: 100%;
}

body {
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.625;
  letter-spacing: -0.002em;
  background: var(--ground);
  color: var(--text);
  overflow-x: hidden;
  transition: background-color var(--theme-t) var(--ease-out),
              color var(--theme-t) var(--ease-out);
}

/* `height: auto` here is load-bearing, do not drop it.
   Every <img> carries width/height attributes (for layout stability). Those
   attributes map to the CSS width/height properties as presentational hints,
   so `height="825"` behaves like `height: 825px` unless an author rule says
   otherwise. With both dimensions definite, `aspect-ratio` is ignored: the
   4/3 card slots rendered at full natural height and the case-study
   screenshots stretched vertically by up to 78%. Rules that genuinely want a
   fixed height (.cs-hero, .bento, .quote-who) set it on a class and still
   win on specificity. */
img, svg, video { display: block; max-width: 100%; height: auto; }

/* The UA default for strong/b is 700, and the page no longer downloads 700.
   600 is the weight this design uses for emphasis everywhere else, so pinning
   it here means dropping the 700 face changes nothing visually and saves a
   font file. Emphasis is used heavily in the systems case studies. */
strong, b { font-weight: 600; }
button, input, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; }

/* The gallery filter sets `card.hidden = true`, but `[hidden]` is only a UA
   rule, so ANY author `display` declaration outranks it. `.work-card` sets
   `display: block`, which silently broke every filter button: cards stayed
   visible and only the count changed. Author-level and !important so no
   component can out-specify it again. */
[hidden] { display: none !important; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

::selection { background: var(--accent); color: var(--ground); }

/* Elements that carry a themed ground animate with the toggle. */
.panel, .card, .rail, .service-card, .plan, .faq-item,
.btn, .pill, .marquee, .compare-col, .work-card {
  transition: background-color var(--theme-t) var(--ease-out),
              border-color var(--theme-t) var(--ease-out),
              color var(--theme-t) var(--ease-out);
}

/* ---------- 3. TYPE ------------------------------------------ */

.display {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(64px, 13vw, 190px);
  line-height: 0.95;
  letter-spacing: -0.045em;
}

h1, .h1 {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(28px, 3.5vw, 50px);
  line-height: 1.1;
  letter-spacing: -0.054em;
}

h2, .h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(20px, 2.4vw, 35px);
  line-height: 1.1;
  letter-spacing: -0.057em;
}

h3, .h3 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(18px, 1.4vw, 20px);
  line-height: 1.3;
  letter-spacing: -0.04em;
}

/* The reference resets tracking rather than scaling it. Do the same. */
@media (max-width: 479px) {
  h1, .h1, h2, .h2, h3, .h3, .display { letter-spacing: normal; }
}

p { max-width: min(62ch, 100%); color: var(--text-2); }

.lead { font-size: 17px; line-height: 1.7; color: var(--text-2); }

/* Mono label system. Every uppercase label on the site uses this. */
.eyebrow, .label, .mono {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* --text-2 not --muted. Muted fails 4.5:1 in both modes. */
  color: var(--text-2);
}

.caption {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-2);
}

.num {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--accent);
}

/* Gold on light ground is 3.4:1. Safe at display sizes only. */
.accent-text { color: var(--accent); }
@media (prefers-contrast: more) {
  :root[data-theme="light"] .accent-text { color: var(--text); }
}

/* ---------- 4. SHELL ----------------------------------------- */

.shell {
  display: grid;
  grid-template-columns: var(--rail-w) 1fr;
  gap: var(--split-gap);
  max-width: 1440px;
  margin-inline: auto;
  align-items: start;
}

.rail {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 20px;
  padding: 22px 20px 22px;
  background: var(--ground);
  /* Safety valve: on short viewports the rail scrolls rather than clipping
     the theme toggle off the bottom. */
  overflow-y: auto;
  scrollbar-width: none;
}
.rail::-webkit-scrollbar { width: 0; }

.content { min-width: 0; }

/* ---------- 5. RAIL PARTS ------------------------------------ */

.rail-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.brand {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 16px;
  letter-spacing: -0.04em;
  color: var(--text);
}

.rail-nav {
  display: flex;
  gap: 4px;
  padding: 4px;
  background: var(--surface-raised);
  border-radius: 60px;
}

.rail-nav a {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-2);
  padding: 5px 10px;
  border-radius: 60px;
  transition: color 0.25s var(--ease), background-color 0.25s var(--ease);
}

.rail-nav a:hover { color: var(--text); }
.rail-nav a[aria-current="page"] { background: var(--text); color: var(--ground); }

.pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px 6px 10px;
  border-radius: 60px;
  background: var(--accent-dim);
  border: 1px solid var(--accent-border);
  margin-bottom: 18px;
}

.pill .caption { color: var(--text); }

.dot {
  width: 7px; height: 7px;
  border-radius: 100%;
  background: var(--ok);
  flex: none;
}

.rail-h1 { margin-bottom: clamp(10px, 1.8vh, 18px); }

.rail-tagline {
  margin-bottom: clamp(10px, 1.8vh, 18px);
  font-size: 15px;
  line-height: 1.6;
  color: var(--text-2);
}

/* Below this the featured card cannot shrink any further without becoming a
   smear, so the headline gives up size instead. */
@media (min-width: 981px) and (max-height: 760px) {
  .rail-h1 { font-size: clamp(24px, 4.6vh, 40px); }
  .rail-tagline { font-size: 14px; }
}
@media (min-width: 981px) and (max-height: 620px) {
  .feat-card { display: none; }
}

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 15px 22px;
  border-radius: 60px;
  background: var(--surface-raised);
  color: var(--text);
  font-size: 16px;
  letter-spacing: -0.04em;
  border: 1px solid transparent;
}

.btn:hover { background: var(--text); color: var(--ground); }

.btn-primary { background: var(--accent); color: #0B0A09; }
.btn-primary:hover { background: var(--text); color: var(--ground); }

.btn-ghost { background: transparent; border-color: var(--border-strong); }
.btn-ghost:hover { background: var(--text); color: var(--ground); border-color: var(--text); }

.btn svg { width: 14px; height: 14px; flex: none; }

/* Featured project card, with literal window chrome.
   This card is the only flexible thing in the rail, so it is what absorbs a
   short viewport. Sized in vh rather than by its aspect ratio, because the
   rail has to end with the contact block and theme toggle on screen at every
   desktop height, not just tall ones. */
.feat-card {
  display: block;
  margin-top: clamp(14px, 2.4vh, 34px);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface);
}

.chrome {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
}

.chrome-dots { display: flex; gap: 6px; }
.chrome-dots i {
  width: 10px; height: 10px; border-radius: 100%;
  border: 1px solid rgba(0, 0, 0, 0.12);
}
.chrome-dots i:nth-child(1) { background: var(--chrome-red); }
.chrome-dots i:nth-child(2) { background: var(--chrome-yellow); }
.chrome-dots i:nth-child(3) { background: var(--chrome-green); }

.feat-card img {
  width: 100%;
  aspect-ratio: 16 / 9;
  max-height: clamp(112px, 19vh, 243px);
  object-fit: cover;
  object-position: left top;
}

.rail-contact { margin-bottom: 14px; }
.rail-contact .eyebrow { display: block; margin-bottom: 8px; }

.email-link {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(22px, 2.2vw, 32px);
  letter-spacing: -0.05em;
  line-height: 1.05;
  display: inline-block;
}

.rail-social {
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

/* Theme toggle */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  margin-top: 14px;
  padding: 3px;
  border: 1px solid var(--border);
  border-radius: 60px;
  background: var(--surface);
}

.theme-toggle span {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-2);
  padding: 5px 12px;
  border-radius: 60px;
  transition: background-color 0.25s var(--ease), color 0.25s var(--ease);
}

:root[data-theme="light"] .theme-toggle .t-light,
:root:not([data-theme="light"]) .theme-toggle .t-dark {
  background: var(--text);
  color: var(--ground);
}

/* ---------- 6. SECTIONS -------------------------------------- */

.section { padding: var(--pad-default) var(--gutter); }
.section--tight { padding-block: var(--pad-tight); }
.section--editorial { padding-block: var(--pad-editorial); }
.section--alt { background: var(--ground-alt); }

.inner { max-width: var(--measure); margin-inline: auto; }

.sec-head { margin-bottom: 48px; }
.sec-head .eyebrow { display: block; margin-bottom: 18px; }

/* Inverted feature panel. Redefines the local token scope so every child
   works in both modes without its own override. */
/* Two panels stacked with their rounded corners touching read as one block
   that has split, not as two cards. Consecutive panels get the same gap the
   shell uses between rail and content, so the seam is deliberate. */
.panel + .panel { margin-top: var(--split-gap); }

.panel {
  background: var(--panel);
  color: var(--on-panel);
  border-radius: 20px;
  box-shadow: inset 0 0 0 1px var(--panel-ring);
  /* Buttons invert to `color: var(--ground)` on hover. Without this the
     panel would hand them the PAGE ground, which is cream in light mode,
     making hovered button text invisible on a cream fill. */
  --ground: var(--panel);
  --text: #EDE8E2;
  --text-2: #B4ADA6;
  --muted: #726C66;
  --surface: #1D1B18;
  --surface-raised: #262320;
  --border: rgba(255, 255, 255, 0.08);
  --border-strong: rgba(255, 255, 255, 0.16);
  --accent: #B8935A;
  --accent-2: #8BAABB;
  --ok: #4DAF84;
}

/* ---------- 7. HERO ------------------------------------------ */

.hero {
  position: relative;
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  place-items: center;
  overflow: hidden;
  isolation: isolate;
}

/* Photograph sits at the bottom of the stack, knocked back hard and warmed
   toward Forge so it reads as atmosphere rather than as a picture. */
/* Knocked back less than it used to be. With the wordmark gone there is no
   type to protect, and the photograph is now the whole hero, so hiding it
   behind a 0.46 veil left the panel looking empty rather than atmospheric. */
.hero-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 38% center;
  opacity: 0.82;
  filter: grayscale(0.18) sepia(0.1) contrast(1.04);
  z-index: 0;
}

/* Scrim plus the gold glow, above the photo and below the type. The scrim is
   what guarantees the wordmark stays legible over any part of the image. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    var(--panel-glow),
    linear-gradient(to bottom,
      rgba(11, 10, 9, 0.42) 0%,
      rgba(11, 10, 9, 0.10) 40%,
      rgba(11, 10, 9, 0.66) 100%);
  pointer-events: none;
  z-index: 1;
}

/* The two words either side of the mark were removed 2026-09-12. With the mark
   alone, space-between would pin it to the left edge, so this centres it. The
   rule still uses flex rather than place-items because the mark keeps its
   scroll-driven rotation and wants a stable box to rotate inside. */
.hero-words {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  width: 100%;
  padding-inline: clamp(20px, 4vw, 52px);
}

.hero-word {
  font-family: var(--font-display);
  font-weight: 800;
  font-style: italic;
  font-size: clamp(26px, 4.2vw, 58px);
  line-height: 0.95;
  letter-spacing: -0.05em;
  white-space: nowrap;
  will-change: transform;
}

.hero-mark {
  width: clamp(44px, 7vw, 104px);
  aspect-ratio: 1;
  flex: none;
  will-change: transform;
}

.hero-scroll {
  position: absolute;
  bottom: 28px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
}

/* ---------- 8. STATS ----------------------------------------- */

.stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin-top: 56px;
}

.stat {
  padding: 28px 24px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
}

.stat-fig {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(28px, 3vw, 40px);
  letter-spacing: -0.05em;
  line-height: 1;
  margin-bottom: 10px;
}

/* ---------- 9. MARQUEE --------------------------------------- */

.marquee {
  overflow: clip;
  padding-block: 28px;
  background: var(--surface);
  border-block: 1px solid var(--border);
}

.marquee-track {
  display: flex;
  align-items: center;
  gap: 60px;
  width: max-content;
  will-change: transform;
}

.marquee-track img {
  height: 26px;
  width: auto;
  opacity: 0.55;
  filter: grayscale(1);
}

:root[data-theme="dark"] .marquee-track img { filter: grayscale(1) invert(1); }

/* --------- 10. WORK GRID ------------------------------------- */

.work-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}

/* An odd final card spans the row rather than leaving a hole. The reference
   ships the same full-width variant for exactly this case. */
.work-grid > :last-child:nth-child(odd) { grid-column: 1 / -1; }
.work-grid > :last-child:nth-child(odd) .work-media img { aspect-ratio: 21 / 9; }

.work-card {
  position: relative;
  display: block;
  border-radius: 20px;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--border);
}

/* These are spans inside an <a> with block children, so they must be made
   block-level or their padding is escaped by the blocks inside them. */
.work-media { display: block; overflow: hidden; }

.work-media img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  will-change: transform;
}

.work-body { display: block; padding: 22px 24px 26px; }

.work-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.work-title { margin-bottom: 8px; }
.work-desc { font-size: 14px; line-height: 1.6; }

.work-cta {
  opacity: 0;
  margin-top: 16px;
  will-change: opacity;
}

/* --------- 11. SERVICES STICKY STACK ------------------------- */

.services-head { position: sticky; top: 24px; z-index: 2; }

.service-box { position: sticky; top: 176px; }
.service-box + .service-box { margin-top: 16px; }

.service-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 15px;
  padding: 32px;
}

.service-card .num { display: block; margin-bottom: 14px; }
.service-card h3 { margin-bottom: 12px; }
.service-card p { font-size: 15px; }

.service-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 20px;
}

.tag {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-2);
  padding: 5px 11px;
  border: 1px solid var(--border);
  border-radius: 60px;
}

/* --------- 12. TESTIMONIALS ---------------------------------- */

.quote-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 34px;
}

.quote-card blockquote {
  font-size: 17px;
  line-height: 1.65;
  color: var(--text);
  margin-bottom: 24px;
}

.quote-who { display: flex; align-items: center; gap: 12px; }
.quote-who img { width: 40px; height: 40px; border-radius: 11px; object-fit: cover; }

/* --------- 13. PRICING --------------------------------------- */

.currency-toggle {
  display: inline-flex;
  padding: 3px;
  border: 1px solid var(--border);
  border-radius: 60px;
  background: var(--surface);
  margin-bottom: 40px;
}

.currency-toggle button {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-2);
  padding: 7px 16px;
  border-radius: 60px;
  transition: background-color 0.25s var(--ease), color 0.25s var(--ease);
}

.currency-toggle button[aria-pressed="true"] { background: var(--text); color: var(--ground); }

.plans { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }

.plan {
  display: flex;
  flex-direction: column;
  padding: 30px 26px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
}

.plan--feature {
  background: var(--panel);
  color: var(--on-panel);
  box-shadow: inset 0 0 0 1px var(--panel-ring);
  --ground: var(--panel);
  --text: #EDE8E2; --text-2: #B4ADA6;
  --surface: #1D1B18; --surface-raised: #262320;
  --border: rgba(255,255,255,0.08); --accent: #B8935A;
}

.plan-price {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(30px, 3vw, 42px);
  letter-spacing: -0.05em;
  line-height: 1;
  margin: 16px 0 6px;
}

.plan ul { margin: 22px 0; display: grid; gap: 10px; }
.plan li { font-size: 14px; color: var(--text-2); padding-left: 22px; position: relative; }
.plan li::before {
  content: "";
  position: absolute; left: 0; top: 8px;
  width: 10px; height: 2px; background: var(--accent);
}
.plan .btn { margin-top: auto; justify-content: center; }

/* --------- 14. COMPARISON ------------------------------------ */

.compare { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }

.compare-col {
  padding: 30px 26px;
  border: 1px solid var(--border);
  border-radius: 20px;
  background: var(--surface);
}

.compare-col--ours {
  background: var(--panel);
  color: var(--on-panel);
  box-shadow: inset 0 0 0 1px var(--panel-ring);
  --ground: var(--panel);
  --text: #EDE8E2; --text-2: #B4ADA6;
  --border: rgba(255,255,255,0.08); --accent: #B8935A;
}

.compare-col h3 { margin-bottom: 20px; }
.compare-col ul { display: grid; gap: 12px; }
.compare-col li {
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-2);
  padding-left: 26px;
  position: relative;
}
.compare-col li::before {
  content: "\2014";
  position: absolute; left: 0; color: var(--muted);
}
.compare-col--ours li::before { content: "\2192"; color: var(--accent); }

/* --------- 15. FAQ ------------------------------------------- */

.faq-list { display: grid; gap: 10px; }

.faq-item {
  border: 1px solid var(--border);
  border-radius: 15px;
  background: var(--surface);
  overflow: hidden;
}

.faq-q {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 20px 24px;
  text-align: left;
  font-size: 16px;
  letter-spacing: -0.02em;
  color: var(--text);
}

.faq-q i {
  flex: none;
  width: 12px; height: 12px;
  position: relative;
  transition: transform 0.35s var(--ease);
}
.faq-q i::before, .faq-q i::after {
  content: ""; position: absolute; background: var(--accent);
  inset-inline: 0; top: 5px; height: 2px;
}
.faq-q i::after { transform: rotate(90deg); }
.faq-item[data-open="true"] .faq-q i { transform: rotate(135deg); }

.faq-a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.4s var(--ease);
}
.faq-item[data-open="true"] .faq-a { grid-template-rows: 1fr; }
.faq-a > div { overflow: hidden; }
.faq-a p { padding: 0 24px 22px; font-size: 15px; }

/* --------- 16. INSIGHTS -------------------------------------- */

.insights { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }

.insight {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  overflow: hidden;
}

.insight img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.insight-body { padding: 20px 22px 24px; }
.insight h3 { font-size: 17px; margin: 10px 0 0; }

/* --------- 16a. FILTERS -------------------------------------- */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 40px;
}

.filters button {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-2);
  padding: 8px 14px;
  border: 1px solid var(--border);
  border-radius: 60px;
  background: var(--surface);
  transition: background-color 0.25s var(--ease), color 0.25s var(--ease),
              border-color 0.25s var(--ease);
}
.filters button:hover { border-color: var(--accent-border); color: var(--text); }
.filters button[aria-pressed="true"] {
  background: var(--text); color: var(--ground); border-color: var(--text);
}

/* A card with nothing to link to yet. Reads as honest, not broken. */
.work-card.is-soon {
  border-style: dashed;
  background: transparent;
}
.work-card.is-soon .work-body { padding-block: 30px; }

/* --------- 16c. FORMS ---------------------------------------- */

.form { display: grid; gap: 20px; max-width: 620px; }

.field { display: grid; gap: 8px; }
.field > label { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em;
                 text-transform: uppercase; color: var(--text-2); }

.input {
  width: 100%;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text);
  font-size: 16px;
  transition: border-color 0.25s var(--ease), background-color 0.25s var(--ease);
}
.input::placeholder { color: var(--muted); }
.input:focus { outline: none; border-color: var(--accent); }
textarea.input { min-height: 132px; resize: vertical; line-height: 1.6; }

.field-error {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: #C0412B;
  display: none;
}
.field.is-invalid .input { border-color: #C0412B; }
.field.is-invalid .field-error { display: block; }

/* Radio and checkbox groups rendered as selectable cards */
.choices { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
.choice { position: relative; }
.choice input { position: absolute; opacity: 0; inset: 0; cursor: pointer; }
.choice span {
  display: block;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 15px;
  transition: border-color 0.25s var(--ease), background-color 0.25s var(--ease);
}
.choice small { display: block; margin-top: 3px; font-size: 13px; color: var(--text-2); }
.choice input:hover + span { border-color: var(--accent-border); }
.choice input:checked + span { border-color: var(--accent); background: var(--accent-dim); }
.choice input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }

.phone-row { display: grid; grid-template-columns: 118px 1fr; gap: 8px; }

/* Multi-step */
.steps { display: flex; gap: 8px; margin-bottom: 40px; flex-wrap: wrap; }
.step-chip {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted);
  padding: 8px 14px; border: 1px solid var(--border); border-radius: 60px;
}
.step-chip[data-state="active"] { color: var(--ground); background: var(--text); border-color: var(--text); }
.step-chip[data-state="done"] { color: var(--accent); border-color: var(--accent-border); }

.step { display: none; }
.step[data-active="true"] { display: block; }

.form-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 8px; }

.form-done { display: none; }
.form-done[data-visible="true"] { display: block; }

@media (max-width: 620px) {
  .choices { grid-template-columns: 1fr; }
  .phone-row { grid-template-columns: 1fr; }
}

/* --------- 16b. CASE STUDY ----------------------------------- */

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 20px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-2);
  transition: color 0.25s var(--ease);
}
.back-link:hover { color: var(--accent); }

.cs-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 18px; }

.cs-meta {
  display: grid;
  gap: 14px;
  margin: 24px 0 28px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}
.cs-meta div { display: grid; gap: 4px; }
.cs-meta dt { font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.1em;
              text-transform: uppercase; color: var(--text-2); }
.cs-meta dd { font-size: 15px; color: var(--text); }

/* Full-bleed opening image for the case study */
.cs-hero {
  position: relative;
  border-radius: 20px;
  overflow: hidden;
  aspect-ratio: 16 / 10;
}
.cs-hero img { width: 100%; height: 100%; object-fit: cover; }

/* A photograph survives being cropped to 16:10. A screenshot does not: cover
   scales it up and eats the interface the image exists to show, taking the
   sidebar and the right-hand column off both edges. Systems studies therefore
   keep the screenshot's own ratio. */
.cs-hero--shot { aspect-ratio: auto; }
.cs-hero--shot img { height: auto; object-fit: fill; }

/* One CAST phase: number and label on the left, argument on the right. */
.cs-phase { display: grid; grid-template-columns: 140px 1fr; gap: 32px; }
.cs-phase + .cs-phase { margin-top: var(--pad-default); }
.cs-phase-side { position: sticky; top: 32px; align-self: start; }
.cs-phase-side .num { display: block; margin-bottom: 8px; }
.cs-phase h2 { margin-bottom: 20px; }
.cs-phase p + p { margin-top: 16px; }

.cs-phase-media { margin-top: 28px; display: grid; gap: 12px; }

/* Systems case studies carry itemised technical detail with no image to stand
   in for it, so the list has to do the work a mockup does elsewhere. Accent
   dash marker, matching .plan li, because `ul` is list-style:none globally. */
.spec-list { display: grid; gap: 12px; margin-top: 22px; }
.spec-list li {
  font-size: 15px;
  line-height: 1.65;
  color: var(--text-2);
  padding-left: 26px;
  position: relative;
}
.spec-list li::before {
  content: "";
  position: absolute; left: 0; top: 11px;
  width: 12px; height: 2px;
  background: var(--accent);
}
.spec-list strong { color: var(--text); font-weight: 600; }

/* Four metrics rather than three. Four cells across the 864px measure leaves
   about 170px of content each, so the padding comes in to stop the captions
   shredding into four lines. */
.stats--quad { grid-template-columns: repeat(4, 1fr); }
.stats--quad .stat { padding: 24px 18px; }
.stats--quad .stat-fig { font-size: clamp(26px, 2.4vw, 34px); }

/* A systems study opens on figures instead of a hero image. */
.cs-lead {
  font-size: 20px;
  line-height: 1.65;
  color: var(--text-2);
  max-width: min(60ch, 100%);
}
.cs-lead strong { color: var(--text); font-weight: 600; }

/* Stack label for the closing "what it runs on" block. */
.stack-grid { display: grid; }
.stack-grid > div {
  display: grid;
  grid-template-columns: 160px 1fr;
  gap: 6px 28px;
  align-items: baseline;
  padding-block: 14px;
  border-top: 1px solid var(--border);
}
.stack-grid dt {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-2);
  padding-top: 4px;
}
.stack-grid dd { font-size: 15px; line-height: 1.6; }
.cs-phase-media img { width: 100%; border-radius: 15px; border: 1px solid var(--border); }

/* Bento gallery. Deliberately uneven so it reads as edited, not dumped. */
.bento {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 12px;
}
.bento figure {
  border-radius: 15px;
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--surface);
  grid-column: span 3;
}
.bento figure:nth-child(6n + 1) { grid-column: span 6; }
.bento figure:nth-child(6n + 4) { grid-column: span 2; }
.bento figure:nth-child(6n + 5) { grid-column: span 4; }
.bento img { width: 100%; height: 100%; object-fit: cover; aspect-ratio: 4 / 3; }
.bento figure:nth-child(6n + 1) img { aspect-ratio: 16 / 7; }

/* The span rhythm above is positional, so it hands out slots without knowing
   what is going in them. A portrait mockup landing in a wide slot gets
   cover-cropped to a sliver: the ATnT360 vertical billboard was sliced
   through its own headline, keeping a quarter of the frame.
   publish-pages.js stamps each figure with the file's real orientation, and
   these rules give it a slot shaped like the picture. Must stay after the
   nth-child rules: same specificity, so source order decides.
   `dense` backfills the holes that re-spanning would otherwise leave. */
.bento { grid-auto-flow: row dense; }
.bento figure.ar-pano { grid-column: span 6; }
.bento figure.ar-pano img { aspect-ratio: 24 / 7; }
.bento figure.ar-portrait { grid-column: span 2; }
.bento figure.ar-portrait img { aspect-ratio: 3 / 4; }
.bento figure.ar-square { grid-column: span 2; }
.bento figure.ar-square img { aspect-ratio: 1; }

.cs-video {
  border-radius: 20px;
  overflow: hidden;
  border: 1px solid var(--border);
}
.cs-video video { width: 100%; display: block; }

.next-project {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
}

@media (max-width: 991px) {
  .cs-phase { grid-template-columns: 1fr; gap: 16px; }
  .cs-phase-side { position: static; }
  .bento { grid-template-columns: repeat(2, 1fr); }
  .bento figure,
  .bento figure:nth-child(6n + 1),
  .bento figure:nth-child(6n + 4),
  .bento figure:nth-child(6n + 5) { grid-column: span 1; }
  .bento figure:nth-child(6n + 1) { grid-column: span 2; }
  /* A media query adds no specificity, so the ar-* spans above would still
     win here and ask for six columns out of two. They have to be restated. */
  .bento figure.ar-portrait,
  .bento figure.ar-square { grid-column: span 1; }
  .bento figure.ar-pano { grid-column: span 2; }
}

@media (max-width: 479px) {
  .bento { grid-template-columns: 1fr; }
  .bento figure,
  .bento figure:nth-child(6n + 1) { grid-column: span 1; }
  .bento figure.ar-portrait,
  .bento figure.ar-square,
  .bento figure.ar-pano { grid-column: span 1; }
}

/* --------- 17. FOOTER ---------------------------------------- */

.site-footer {
  margin-top: 12px;
  padding: var(--pad-default) var(--gutter) 40px;
  border-radius: 20px 20px 0 0;
}

.footer-logotype {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(52px, 15vw, 168px);
  line-height: 0.9;
  letter-spacing: -0.055em;
  text-align: center;
  margin-bottom: 48px;
}

.footer-grid {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  gap: 40px;
  padding-top: 40px;
  border-top: 1px solid var(--border);
}

.footer-grid h4 { margin-bottom: 14px; }
.footer-grid li + li { margin-top: 8px; }
/* Must exclude .btn: a bare  outranks  and
   silently repaints the button, including an invisible hover state. */
.footer-grid a:not(.btn) { font-size: 14px; color: var(--text-2); }
.footer-grid a:not(.btn):hover { color: var(--text); }

.footer-base {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  justify-content: space-between;
  margin-top: 48px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
}

/* --------- 18. REVEAL STATES --------------------------------- */
/* Hidden only while JS is present AND the motion system reported for duty.
   site.js adds .no-motion if GSAP failed to load or motion is reduced, which
   makes every hidden element visible again. A broken script never blanks
   the page. */

html.js:not(.no-motion) [data-reveal],
html.js:not(.no-motion) [data-reveal-group] > * {
  opacity: 0;
  transform: translateY(3rem);
}

.split-mask {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  line-height: inherit;
}

.split-letter { display: inline-block; will-change: transform; }

/* Two stacked copies of a letter. Rolling the stack up by 50% swaps one
   for the other inside the mask, so the mask must be exactly one line tall
   or both copies show at once. */
.split-stack {
  display: flex;
  flex-direction: column;
  will-change: transform;
}

.split-mask--roll { height: 1em; }
.split-mask--roll .split-letter { line-height: 1; }

/* --------- 19. RESPONSIVE ------------------------------------ */

@media (max-width: 991px) {
  :root { --gutter: 24px; --pad-default: 88px; --pad-tight: 56px; --pad-editorial: 120px; }

  .shell { grid-template-columns: 1fr; gap: 0; }

  /* The rail stops being sticky and becomes a header plus a footer block. */
  .rail {
    position: static;
    height: auto;
    display: grid;
    grid-template-areas: "head" "main";
    padding: 20px var(--gutter) 40px;
  }
  .rail-head { grid-area: head; margin-bottom: 40px; }
  .rail-main { grid-area: main; margin: 0; }
  .rail-foot { display: none; }

  /* Its contact half is re-rendered inside the footer instead. */
  .footer-contact { display: block; }

  .stats { grid-template-columns: 1fr; }
  /* Four stacked cards is a lot of scrolling for four numbers. */
  .stats--quad { grid-template-columns: repeat(2, 1fr); }
  .work-grid, .compare, .plans, .insights { grid-template-columns: 1fr; }
  .service-box { position: static; }
  .service-box + .service-box { margin-top: 12px; }
  .services-head { position: static; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
}

@media (min-width: 992px) {
  .footer-contact { display: none; }
}

@media (max-width: 479px) {
  :root { --pad-default: 60px; --pad-tight: 44px; --pad-editorial: 80px; }
  .section { padding-inline: var(--gutter); }
  .service-card, .plan, .compare-col, .quote-card { padding: 24px 20px; }
  .footer-grid { grid-template-columns: 1fr; }
  .stack-grid > div { grid-template-columns: 1fr; }
  .cs-lead { font-size: 17px; }

  /* The nav pills cannot sit beside the wordmark at this width without
     pushing the document wider than the viewport. */
  .rail-head { flex-direction: column; align-items: flex-start; gap: 14px; }
  .rail-nav { flex-wrap: wrap; }
  .rail-social { gap: 14px; }
}

/* Nothing may make the document wider than the viewport. */
html, body { max-width: 100%; }
.marquee, .hero { max-width: 100%; }

/* --------- 20. REDUCED MOTION -------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html [data-reveal],
  html [data-reveal-group] > * { opacity: 1 !important; transform: none !important; }

  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

@media print {
  .rail-nav, .theme-toggle, .marquee, .hero-scroll { display: none; }
}
