/* =============================================================================
   Best Practice — shared stylesheet
   -----------------------------------------------------------------------------
   Every studio page (/, /apps, /sites, /contact) loads this one file. It used to
   be ~250 lines of <style> duplicated into each page plus the Tailwind Play CDN,
   which shipped a 407KB CSS compiler to the browser on every visit to generate
   the ~40 utilities below. Play CDN is documented as a development-only tool, so
   the utilities are written out by hand here instead: one cached request for the
   whole site, and no compiler on the critical path.

   Section 1 is the subset of Tailwind's Preflight the markup actually depends
   on — the pages were authored against it, so dropping it wholesale would change
   heading sizes and spacing. Section 2 is the utilities, emitted in Tailwind's
   property order so same-specificity conflicts (p-6 vs md:px-10) resolve the way
   they always did. Sections 3+ are this site's own components, unchanged.
   ========================================================================== */


/* --- 1. PREFLIGHT (subset of Tailwind v3) --------------------------------- */

*,
::before,
::after {
  box-sizing: border-box;
  border-width: 0;
  border-style: solid;
  border-color: currentColor;
}

html {
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
  tab-size: 4;
  font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
    "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
}

body {
  margin: 0;
  line-height: inherit;
}

/* Headings inherit size and weight; the pages set both with utilities or with a
   component class, so anything the browser would default to is unwanted. */
h1, h2, h3, h4, h5, h6 {
  font-size: inherit;
  font-weight: inherit;
  margin: 0;
}

p, figure, blockquote, dl, dd, hr, pre {
  margin: 0;
}

a {
  color: inherit;
  text-decoration: inherit;
}

b, strong {
  font-weight: bolder;
}

img, svg, video, canvas, audio, iframe, embed, object {
  display: block;
  vertical-align: middle;
}

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


/* --- 2. UTILITIES --------------------------------------------------------- */

.fixed { position: fixed; }
.top-0 { top: 0; }
.left-0 { left: 0; }
.z-50 { z-index: 50; }

.mx-auto { margin-left: auto; margin-right: auto; }
.mb-5 { margin-bottom: 1.25rem; }
.mb-6 { margin-bottom: 1.5rem; }
.mb-16 { margin-bottom: 4rem; }
.mb-20 { margin-bottom: 5rem; }

.flex { display: flex; }
.min-h-screen { min-height: 100vh; }
.w-full { width: 100%; }
.max-w-lg { max-width: 32rem; }
.max-w-4xl { max-width: 56rem; }

.flex-col { flex-direction: column; }
.items-center { align-items: center; }
.justify-start { justify-content: flex-start; }
.justify-between { justify-content: space-between; }
.gap-6 { gap: 1.5rem; }

.p-6 { padding: 1.5rem; }
.px-6 { padding-left: 1.5rem; padding-right: 1.5rem; }
.pt-28 { padding-top: 7rem; }
.pt-\[25vh\] { padding-top: 25vh; }

.text-center { text-align: center; }

.text-sm { font-size: 0.875rem; line-height: 1.25rem; }
.text-base { font-size: 1rem; line-height: 1.5rem; }
.text-4xl { font-size: 2.25rem; line-height: 2.5rem; }

.font-normal { font-weight: 400; }
.font-bold { font-weight: 700; }

.leading-relaxed { line-height: 1.625; }
.leading-\[1\.1\] { line-height: 1.1; }

.tracking-wider { letter-spacing: 0.05em; }
.tracking-\[-0\.015em\] { letter-spacing: -0.015em; }

.opacity-80 { opacity: 0.8; }

/* Tailwind's `md` breakpoint. Emitted after the base utilities so the responsive
   variants win at width, exactly as the generated stylesheet ordered them. */
@media (min-width: 768px) {
  .md\:px-10 { padding-left: 2.5rem; padding-right: 2.5rem; }
  .md\:py-8 { padding-top: 2rem; padding-bottom: 2rem; }
  .md\:pt-32 { padding-top: 8rem; }
  .md\:pt-\[30vh\] { padding-top: 30vh; }
  .md\:text-lg { font-size: 1.125rem; line-height: 1.75rem; }
  .md\:text-5xl { font-size: 3rem; line-height: 1; }
}


/* --- 3. THEME + PAGE CHROME ----------------------------------------------- */

/* These control the colour theme. The JavaScript updates '--theme-hue'. */
@property --page-background {
  syntax: '<color>';
  inherits: true;
  initial-value: #f0f4f8;
}
@property --main-text-color {
  syntax: '<color>';
  inherits: true;
  initial-value: #2a323c;
}
@property --glow-color {
  syntax: '<color>';
  inherits: true;
  initial-value: #e6eef5;
}

:root {
  --theme-hue: 210;

  --target-page-background: hsl(var(--theme-hue), 32%, 96%);
  --target-main-text-color: hsl(var(--theme-hue), 24%, 22%);
  --target-glow-color: hsl(var(--theme-hue), 40%, 92%);

  --page-background: var(--target-page-background);
  --main-text-color: var(--target-main-text-color);
  --glow-color: var(--target-glow-color);

  transition: --page-background 1.5s ease, --main-text-color 1.5s ease, --glow-color 1.5s ease;
}

body {
  /* Makes text look sharper on high-res screens */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;

  font-family: 'Libre Baskerville', serif;

  background-color: var(--page-background);
  background-image: radial-gradient(circle at 48px 48px, var(--glow-color) 0%, var(--page-background) 80%);
  background-attachment: fixed;

  color: var(--main-text-color);

  /* Force scrollbar to prevent horizontal jumps between pages */
  overflow-y: scroll;

  /* Fallback transitions for older browsers (modern browsers will animate
     --theme-hue natively). */
  transition: background-color 1.5s ease, color 1.5s ease;
}

/* Prevents headlines from leaving a single word on a new line (orphan) */
.prevent-hanging-words { text-wrap: balance; }

/* --- NAV ---
   The bar is fixed and has no background of its own, so on a long page the
   content scrolled underneath it and collided with the links — on /apps the
   Sampultu card ran straight through "Apps / Sites / Client Clubhouse". This
   scrim fades in only once the page has actually moved, so the top of every
   page still opens as bare type on the gradient. */
.site-nav::before {
  content: '';
  position: absolute;
  /* Runs past the bottom of the bar so the fade finishes below it. Ending the
     gradient flush with the nav lands the half-faded band directly on the card
     titles passing underneath, which reads as a rendering fault rather than a
     deliberate wash. */
  inset: 0 0 -2.25rem 0;
  z-index: -1;
  pointer-events: none;
  /* Flat fill + a mask for the fade, rather than a gradient between two stops
     derived from --page-background. That property is registered via @property
     and animates on every hue change, and interpolating it inside a gradient
     forces a full recalc of the painted image each frame. The mask is plain
     black-to-transparent, so the fade is free and only the flat colour moves. */
  background: var(--page-background);
  -webkit-mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 62%, transparent 100%);
  opacity: 0;
  transition: opacity 0.3s ease;
}

body[data-scrolled] .site-nav::before { opacity: 1; }

.client-login-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--main-text-color);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.28em;
  text-decoration-color: color-mix(in srgb, var(--main-text-color) 42%, transparent);
  transition: text-decoration-color 0.3s ease;
}

.client-login-link:hover { text-decoration-color: var(--main-text-color); }

.client-login-link:focus-visible {
  outline: 2px solid var(--main-text-color);
  outline-offset: 2px;
  border-radius: 4px;
}

/* --- FOOTER ---
   margin-top:auto against the body's flex column, so on a short page (the
   homepage is one heading and one line) it settles on the bottom of the
   viewport instead of floating under the text, and on a long one it simply
   follows the content. --- */
.site-footer {
  margin-top: auto;
  width: 100%;
  padding: 2rem 0 2.5rem;
  text-align: center;
  font-size: 0.8125rem;
}

/* A short rule instead of a full-width border: enough to seat the links
   without drawing a hard line across the page. */
.site-footer::before {
  content: '';
  display: block;
  width: 3rem;
  height: 1px;
  margin: 0 auto 1.6rem;
  background: color-mix(in srgb, var(--main-text-color) 25%, transparent);
}

.site-footer-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.5rem 1.5rem;
}

.footer-link {
  color: var(--main-text-color);
  opacity: 0.7;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.25em;
  text-decoration-color: color-mix(in srgb, var(--main-text-color) 35%, transparent);
  transition: opacity 0.3s ease, text-decoration-color 0.3s ease;
}

.footer-link:hover {
  opacity: 1;
  text-decoration-color: var(--main-text-color);
}

.footer-link:focus-visible {
  outline: 2px solid var(--main-text-color);
  outline-offset: 3px;
  border-radius: 3px;
}

/* The current page still gets a link (it is a real destination from every
   other page) but is marked and de-emphasised rather than duplicated. */
.footer-link[aria-current="page"] {
  opacity: 0.45;
  text-decoration-color: transparent;
}


/* --- 4. SITE GALLERY ---
   Same card anatomy as the app grid below, but a site reads as the page itself,
   so the tile is a wide 1108:808 frame rather than a 96px icon. --- */

.site-grid {
  display: grid;
  /* Same track sizing as .app-grid so both pages share one rhythm. auto-FILL
     rather than auto-fit: auto-fit collapses the empty tracks and lets a single
     card stretch across the whole row, which centres it. auto-fill keeps the
     empty columns, so one site sits in column 1 exactly where the first app
     does. */
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 3.5rem 1.75rem;
}

.site-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 1rem;
}

.site-thumb-link {
  display: block;
  width: 100%;
  border-radius: 14px;
  /* Clip the video to the rounded corners on Safari, which ignores the child's
     border-radius once the element is composited for playback. */
  overflow: hidden;
  -webkit-mask-image: -webkit-radial-gradient(#fff, #000);
  border: 1px solid color-mix(in srgb, var(--main-text-color) 16%, transparent);
  transition: transform 0.15s ease-out;
}

.site-thumb-link:hover { transform: translateY(-2px); }

.site-thumb-link:focus-visible {
  outline: 2px solid var(--main-text-color);
  outline-offset: 3px;
}

.site-thumb {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1108 / 808;
  object-fit: cover;
  /* Holds the frame's own colour while the poster loads, so the card never
     flashes the page background at a different size. */
  background: #bff0e2;
}

.store-btn-label { font-size: 0.9rem; font-weight: 600; }


/* --- 5. APP GALLERY ------------------------------------------------------- */

.app-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 3.5rem 1.75rem;
}

.app-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 1rem;
}

/* App icon tile */
.app-icon {
  width: 96px;
  height: 96px;
  border-radius: 22px;
  object-fit: cover;
}

/* Logos designed for a dark backdrop (e.g. Static Radio) */
.app-icon--dark {
  object-fit: contain;
  padding: 12px;
  background: #050608;
}

/* Emoji-based icon tile (e.g. Emojio, a web app with no store artwork) */
.app-icon--emoji {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 52px;
  line-height: 1;
  background: color-mix(in srgb, var(--main-text-color) 10%, #ffffff);
}

.app-name {
  font-size: 1.25rem;
  line-height: 1.25;
  min-height: 2.5em;
  text-wrap: balance;
  margin: 0;
}

.app-tagline {
  opacity: 0.78;
  line-height: 1.5;
  font-size: 0.95rem;
  max-width: 32ch;
  min-height: 4.5em;
  text-wrap: balance;
  margin: 0;
}

/* --- SUITE BAND ---
   The five Plumb apps sit in their own grid below the rest, introduced by this
   band, so the suite reads as one product family rather than five unrelated
   cards. --- */
.suite {
  margin: 5.5rem auto 3rem;
  max-width: 44ch;
  text-align: center;
}

.suite-title {
  font-size: 1.75rem;
  line-height: 1.2;
  margin: 0 0 0.85rem;
}

.suite-lede {
  font-size: 0.95rem;
  line-height: 1.65;
  opacity: 0.78;
  text-wrap: pretty;
  margin: 0;
}

/* Store buttons: unified row at bottom */
.store-row {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: center;
  gap: 0.55rem;
  margin-top: auto;
  padding-top: 0.9rem;
  width: 100%;
}

.store-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 0.55rem 0.9rem;
  border: 1px solid var(--main-text-color);
  border-radius: 9px;
  color: var(--main-text-color);
  background: transparent;
  text-decoration: none;
  text-align: left;
  line-height: 1.1;
  transition: background-color 0.3s ease, transform 0.15s ease-out;
}

.store-btn:hover {
  background: color-mix(in srgb, var(--main-text-color) 9%, transparent);
  transform: translateY(-1px);
}

.store-btn:focus-visible {
  outline: 2px solid var(--main-text-color);
  outline-offset: 2px;
}

.store-btn svg { width: 20px; height: 20px; flex-shrink: 0; }
.store-btn .btn-main { font-size: 0.9rem; font-weight: 700; }


/* --- 6. CONTACT ----------------------------------------------------------- */

.contact-block {
  max-width: 40ch;
  margin: 0 auto;
  text-align: center;
}

.contact-email {
  display: inline-block;
  /* Scales to fit rather than wrapping: an address broken across two lines is
     hard to read and worse to copy by hand.

     The floor used to be 1rem against 3.4vw, which meant that below ~470px the
     clamp pinned at 16px and stopped scaling — but the address still needs
     ~282px at that size and a 320px phone only offers 272px after the page
     gutters. The nowrap text spilled past its own box and scrolled the whole
     page sideways. A lower floor and a steeper slope keep it scaling all the
     way down; the cap is unchanged, so it looks the same on a desktop. */
  font-size: clamp(0.85rem, 4vw, 1.5rem);
  white-space: nowrap;
  max-width: 100%;
  color: var(--main-text-color);
  text-decoration: underline;
  text-underline-offset: 0.3em;
  text-decoration-color: color-mix(in srgb, var(--main-text-color) 42%, transparent);
  transition: text-decoration-color 0.3s ease;
}

.contact-email:hover { text-decoration-color: var(--main-text-color); }

.contact-email:focus-visible {
  outline: 2px solid var(--main-text-color);
  outline-offset: 4px;
  border-radius: 4px;
}

.contact-note {
  margin: 1.5rem 0 0;
  font-size: 0.95rem;
  line-height: 1.6;
  opacity: 0.78;
  text-wrap: pretty;
}


/* --- 7. ACCESSIBILITY ----------------------------------------------------- */

/* Turn off animations if the user requests reduced motion. */
@media (prefers-reduced-motion: reduce) {
  *, ::before, ::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
