/*
 * Code Nursery — the thin layer on top of Bootstrap 5.
 * Bootstrap and Bootstrap Icons are vendored alongside this file; everything
 * here is site-specific and safe to edit.
 */

/* --- Ubuntu ------------------------------------------------------------- *
 * The logo's wordmark is closest to Ubuntu, so headings and the brand use it
 * to match. Self-hosted (latin subset, ~14 KB per weight) rather than loaded
 * from Google Fonts, so the site makes no third-party requests. Licence:
 * Ubuntu Font Licence 1.0 — see /fonts/UBUNTU-FONT-LICENCE.txt.
 */

@font-face {
  font-family: "Ubuntu";
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("/fonts/ubuntu-300.woff2") format("woff2");
}

@font-face {
  font-family: "Ubuntu";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/ubuntu-400.woff2") format("woff2");
}

@font-face {
  font-family: "Ubuntu";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/fonts/ubuntu-500.woff2") format("woff2");
}

@font-face {
  font-family: "Ubuntu";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/fonts/ubuntu-700.woff2") format("woff2");
}

:root {
  --cn-green: rgb(148 173 21);
  --cn-green-dark: rgb(110 129 16);

  /* Display face: headings, the navbar brand, buttons. Body text stays on the
     system stack, which costs nothing to load and reads well at small sizes. */
  --cn-font-brand: "Ubuntu", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* The page's horizontal breathing room. One variable because the navbar and
     the full-bleed screenshot strip both cancel it out with negative margins,
     and those have to stay in step with it. */
  --cn-gutter: 1rem;
}

@media (min-width: 768px) {
  :root {
    --cn-gutter: 1.5rem;
  }
}

h1,
h2,
h3,
h4,
h5,
h6,
.navbar-brand,
.btn,
.lead {
  font-family: var(--cn-font-brand);
}

/* The wordmark is tracked tightly; default spacing reads looser than the logo. */
h1,
h2,
.navbar-brand {
  letter-spacing: -0.015em;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/*
 * `.page-shell` is `col-sm-10 mx-auto` in the markup, which centres it from the
 * `sm` breakpoint up. A Bootstrap column only gets its padding from `.row > *`,
 * though, and this one is not in a row — so below `sm` it had no gutter at all
 * and text ran into both edges of the phone. The padding lives here instead.
 */
.page-shell {
  display: flex;
  flex-direction: column;
  flex: 1 0 auto;
  padding-inline: var(--cn-gutter);
  padding-bottom: 1rem;

  /*
   * The shell is a flex item of `body`, so its width is the flex *cross* axis —
   * and a stretched item is still floored by its max-content width there.
   * `.shot-strip` is 1000px+ wide at max-content, so without this cap the shell
   * grew to fit it, the strip's own `overflow-x: auto` never had a narrower box
   * to scroll inside, and the whole landing page scrolled sideways on a phone.
   * `min-width: 0` is the usual cure for this and does nothing here: it applies
   * to the main axis, which for a column flex container is the vertical one.
   */
  max-width: 100%;
}

main {
  flex: 1 0 auto;
}

/* --- Navigation --------------------------------------------------------- */

/*
 * The navbar is a tab attached to the top of the page, so it cancels the
 * shell's gutter and spans it edge to edge. Its own inner padding is then set
 * to the same gutter, which lines the brand and the links up with the content
 * below rather than leaving them 0.75rem out of step.
 */
.site-nav {
  margin-inline: calc(var(--cn-gutter) * -1);
  border-radius: 0 0 0.5rem 0.5rem;
}

.site-nav > .container-fluid {
  padding-inline: var(--cn-gutter);
}

.site-nav .navbar-brand,
.site-nav .nav-link {
  color: var(--cn-nav-text, #1c2405);
}

/* Weight 500 to match the wordmark — Ubuntu has no 600, and the browser would
   otherwise substitute 700, which reads heavier than the logo. */
.site-nav .navbar-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 500;
}

/* On a subsite the brand is two links — the logo home, the title to the
   subsite — so they inherit the navbar's colour rather than Bootstrap's. */
.site-nav .navbar-brand a {
  display: inline-flex;
  align-items: center;
  color: inherit;
  text-decoration: none;
}

.site-nav .navbar-brand a:hover,
.site-nav .navbar-brand a:focus {
  color: inherit;
  text-decoration: underline;
}

.site-nav .nav-link:hover,
.site-nav .nav-link:focus {
  color: var(--cn-nav-text, #1c2405);
  text-decoration: underline;
}

.site-nav .nav-link.active {
  font-weight: 600;
  text-decoration: underline;
}

/* Below `md` the navbar collapses and these links become the only way around
   the site, so they get a 44px touch target — Bootstrap's default padding
   leaves them about 30px tall, which is a fiddly thing to hit with a thumb. */
@media (max-width: 767.98px) {
  .site-nav .navbar-nav .nav-link {
    display: flex;
    align-items: center;
    min-height: 44px;
  }

  .site-nav .navbar-toggler {
    min-width: 44px;
    min-height: 44px;
  }

  /* On a subsite the brand is two separate links — the logo home and the title
     to the subsite — so they are navigation too, and get the same target. The
     logo's is 32px square and the title's 30px tall without this. */
  .site-nav .navbar-brand a {
    min-height: 44px;
  }

  /* Bootstrap's default button comes out 38px tall, which is under the same
     44px floor the nav already keeps to. `inline-flex` rather than extra
     padding so the label stays centred in the taller box. `.app-store-btn`
     sets its own display later in this file and is unaffected. */
  .btn:not(.navbar-toggler) {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
  }
}

.skip-link {
  display: inline-block;
  padding: 0.5rem 1rem;
  background: #fff;
}

/* --- Page furniture ----------------------------------------------------- */

.page-title {
  margin-top: 1.5rem;
}

/* `min-width` is capped at the container's own width — a flat 300px overflowed
   the shell on a 320px-wide phone and gave the home page a sideways scroll. */
.hero-logo {
  width: 60%;
  min-width: min(300px, 100%);
  margin-top: 1.5rem;
}

.site-footer {
  flex-shrink: 0;
  margin-top: 2.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--bs-border-color);
  font-size: 0.875rem;
  font-weight: 300;
}

/* --- Products ----------------------------------------------------------- */

.product-icon {
  font-size: 1.75rem;
  line-height: 1;
  color: var(--cn-green-dark);
}

/* The platform icons on a product card — a phone and a tablet for an app that
   ships on iOS and iPadOS. */
.product-platforms {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 1.75rem;
  line-height: 1;
  color: var(--cn-green-dark);
}

.product-card .card-footer {
  background: transparent;
}

.product-card a {
  text-decoration: none;
}

.product-card a:hover {
  text-decoration: underline;
}

/* --- App landing page --------------------------------------------------- *
 * The components a product subsite's front page is built from: hero, feature
 * grid, screenshot strip, testimonials, closing call to action. Nothing here is
 * VoiceBox-specific — the accent colour comes from --app-accent, so a second
 * subsite can reuse the lot by overriding that one variable.
 *
 * Written mobile-first: the base rules are the phone layout, and the `min-width`
 * blocks add the room a bigger screen can afford.
 */

.app-hero {
  --app-accent: rgb(173 216 230);
  --app-accent-deep: #0b2530;

  /* The colour wash sits over --app-hero-image so white text stays readable
     whatever the photograph underneath is doing. With no image set, the
     gradient is the background. */
  position: relative;
  margin-top: 1.25rem;
  padding: 2.25rem 1.25rem;
  border-radius: 1rem;
  background-color: var(--app-accent-deep);
  background-image: linear-gradient(160deg, rgb(11 37 48 / 82%), rgb(11 37 48 / 94%)),
    var(--app-hero-image, none);
  background-size: cover;
  background-position: center;
  color: #fff;
  text-align: center;
}

@media (min-width: 768px) {
  .app-hero {
    margin-top: 1.5rem;
    padding: 3rem 1.5rem;
  }
}

.app-hero-body {
  max-width: 34rem;
  margin: 0 auto;
}

/* The icon, real or placeholder, at the App Store's own corner radius (22.5% of
   the side) so it reads as an app icon at a glance. The radius is a percentage
   rather than a fixed 25px so it stays correct at the smaller phone size. */
.app-icon,
.app-icon-placeholder {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 88px;
  height: 88px;
  margin-bottom: 1.25rem;
  border-radius: 22.5%;
  box-shadow: 0 0.75rem 1.5rem rgb(0 0 0 / 35%);
}

@media (min-width: 768px) {
  .app-icon,
  .app-icon-placeholder {
    width: 112px;
    height: 112px;
  }
}

.app-icon-placeholder {
  border: 2px dashed rgb(255 255 255 / 45%);
  background: rgb(255 255 255 / 10%);
  font-size: 2.75rem;
  line-height: 1;
  color: var(--app-accent);
}

.app-hero-title {
  margin-bottom: 0.5rem;
  font-size: clamp(2.5rem, 8vw, 3.5rem);
  font-weight: 700;
}

/* The one line that has to land. Sized between the title and the body copy so
   the eye reads title → promise → detail without being told to. */
.app-hero-cta-line {
  margin-bottom: 1rem;
  font-family: var(--cn-font-brand);
  font-size: clamp(1.25rem, 4vw, 1.6rem);
  font-weight: 300;
  line-height: 1.3;
  color: var(--app-accent);
}

.app-hero-description {
  margin-bottom: 2rem;
  color: rgb(255 255 255 / 88%);
}

.app-hero-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
}

.app-hero-meta {
  font-size: 0.875rem;
  color: rgb(255 255 255 / 70%);
}

.app-hero-badge {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid rgb(255 255 255 / 15%);
  font-size: 0.875rem;
}

.app-hero-badge-text {
  color: rgb(255 255 255 / 75%);
}

.app-hero-badge-text a {
  color: var(--app-accent);
}

/* Both call-to-action buttons are the same object in two places, so they are
   styled once and never allowed to drift apart.

   On a phone it goes full width. "Download on the App Store" at `btn-lg` is
   wider than a 375px screen once the hero's padding is taken off, and a
   stretched button is a better answer than a wrapped or clipped label — it is
   also the easiest thing on the page to hit with a thumb, which is what the
   whole page is asking the visitor to do. */
.app-store-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  width: 100%;
  min-height: 44px;
  padding: 0.75rem 1.25rem;
  border-radius: 0.6rem;
  font-weight: 500;
  text-wrap: balance;
}

@media (min-width: 576px) {
  .app-store-btn {
    display: inline-flex;
    width: auto;
    padding-inline: 1.75rem;
  }
}

.app-store-btn .bi {
  flex-shrink: 0;
  font-size: 1.4rem;
  line-height: 1;
}

/* --- Sections on the landing page --------------------------------------- */

.app-section {
  margin-top: 2.5rem;
}

@media (min-width: 768px) {
  .app-section {
    margin-top: 3.5rem;
  }
}

.app-section-title {
  margin-bottom: 0.25rem;
}

.app-section-lede {
  margin-bottom: 1.5rem;
  font-family: var(--cn-font-brand);
  font-weight: 300;
  color: var(--bs-secondary-color);
}

.feature-card {
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.feature-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--bs-box-shadow-sm);
}

@media (prefers-reduced-motion: reduce) {
  .feature-card {
    transition: none;
  }

  .feature-card:hover {
    transform: none;
  }
}

/* --- Screenshots --------------------------------------------------------- *
 * A single row that scrolls sideways rather than a grid that reflows: phone
 * screenshots are meant to be read in order, and scrolling keeps that order on
 * every width. Snap points stop it drifting between two frames.
 */

/*
 * The strip cancels the shell's gutter and re-adds it as padding, so on a phone
 * the frames scroll from edge to edge and the first one still lines up with the
 * text above it. Without that the strip would stop short of the screen edge and
 * look like it had simply been cut off rather than invited a swipe.
 */
.shot-strip {
  display: flex;
  gap: 1rem;
  margin-bottom: 0;
  margin-inline: calc(var(--cn-gutter) * -1);
  padding-inline: var(--cn-gutter);
  padding-bottom: 1rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--cn-gutter);
  scrollbar-width: thin;
}

/* Capped at 15rem but allowed to shrink with the viewport, so a narrow phone
   always shows part of the next frame — the cue that there is more to swipe to. */
.shot {
  flex: 0 0 auto;
  width: min(15rem, 62vw);
  scroll-snap-align: start;
}

.shot-image,
.shot-placeholder {
  width: 100%;
  aspect-ratio: 9 / 19.5;
  border-radius: 1.25rem;
}

/* iPad screenshots: wider frames, so fewer fit across, but the same idea —
   on a phone part of the next frame always shows. */
.shot-strip--ipad .shot {
  width: min(22rem, 72vw);
}

.shot-strip--ipad .shot-image,
.shot-strip--ipad .shot-placeholder {
  aspect-ratio: 3 / 4;
}

.shot-strip--ipad-landscape .shot {
  width: min(30rem, 80vw);
}

.shot-strip--ipad-landscape .shot-image,
.shot-strip--ipad-landscape .shot-placeholder {
  aspect-ratio: 4 / 3;
}

.shot-image {
  height: auto;
  box-shadow: 0 0.5rem 1.25rem rgb(0 0 0 / 18%);
}

.shot-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  border: 2px dashed var(--bs-border-color);
  background: var(--bs-tertiary-bg);
  font-size: 2rem;
  color: var(--bs-secondary-color);
}

.shot-placeholder span {
  font-size: 0.875rem;
}

.shot-caption {
  margin: 0.75rem 0 0;
  font-family: var(--cn-font-brand);
  font-size: 0.9375rem;
  font-weight: 500;
  text-align: center;
  text-wrap: balance;
}

/* --- Testimonials -------------------------------------------------------- */

.testimonial .card-body {
  display: flex;
  flex-direction: column;
}

.testimonial blockquote {
  flex: 1 0 auto;
}

.testimonial-mark {
  margin-bottom: 0;
  font-size: 2rem;
  line-height: 1;
  color: var(--cn-green-dark);
}

.testimonial-source {
  display: flex;
  flex-direction: column;
  font-size: 0.875rem;
}

.testimonial-name {
  font-family: var(--cn-font-brand);
  font-weight: 500;
}

.testimonial-role {
  color: var(--bs-secondary-color);
}

/* --- Closing call to action ---------------------------------------------- */

.app-cta {
  margin-top: 2.5rem;
  padding: 2rem 1.25rem;
  border: 1px solid var(--bs-border-color);
  border-radius: 1rem;
  background: var(--bs-tertiary-bg);
  text-align: center;
}

@media (min-width: 768px) {
  .app-cta {
    margin-top: 3.5rem;
    padding: 2.5rem 1.5rem;
  }
}

.app-cta-title {
  margin-bottom: 0.5rem;
}

.app-cta-text {
  margin-bottom: 1.5rem;
  color: var(--bs-secondary-color);
}

.app-cta-links {
  margin-top: 1.5rem;
  font-size: 0.9375rem;
}

/* --- Long-form content -------------------------------------------------- */

/*
 * Headings in Markdown pages (privacy, terms, how-to, guides, blog posts).
 * Bootstrap's sizes sit close together, so each level here differs in size,
 * weight and the space above it, making it obvious where a section starts.
 * `:not([class])` leaves alone headings in templates that set their own
 * look, such as the home page's `<h2 class="h4">`.
 */
.blog-post h2,
main > h2:not([class]) {
  margin-top: 3rem;
  margin-bottom: 1rem;
  font-size: calc(1.325rem + 0.9vw);
  font-weight: 700;
}

.blog-post h3,
main > h3:not([class]) {
  margin-top: 2.25rem;
  margin-bottom: 0.75rem;
  font-size: 1.375rem;
  font-weight: 500;
}

.blog-post h4,
main > h4:not([class]) {
  margin-top: 1.75rem;
  margin-bottom: 0.5rem;
  color: var(--bs-secondary-color);
  font-size: 0.875rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* A heading straight after a divider already has the divider's space above it. */
main > hr + h2:not([class]) {
  margin-top: 0;
}

main > hr {
  margin: 2.5rem 0;
}

@media (min-width: 1200px) {
  .blog-post h2,
  main > h2:not([class]) {
    font-size: 2rem;
  }
}

/* Images in posts scale down to the column, never up. */
.blog-post img {
  max-width: 100%;
  height: auto;
}

.how-to-steps {
  padding-left: 1.25rem;
}

.how-to-steps > li {
  margin-bottom: 1.25rem;
}

.how-to-steps > li::marker {
  color: var(--cn-green-dark);
  font-weight: 700;
}
