/* Guayaba Education — marketing site styles.
   Brand tokens are fixed (see SITE-HOME.md): do not substitute. */

:root {
  --green: #40534D;
  --teal: #138072;      /* darkened from #14897A for 4.5:1 AA contrast */
  --orange: #E08A4F;
  --gold: #E8A923;
  --cream: #F9F8F4;
  --logo-gold: #F7CF4A;
  --orange-text: #A16339; /* orange for text on cream — AA-compliant shade of #E08A4F */
  --gold-text: #F8B525;   /* gold for text on dark green — AA-compliant shade of #E8A923 */
  --orange-light: #F2B884; /* orange for marks on dark green — AA-compliant shade of #E08A4F */
  --ink: #2E3B36;          /* darkened green for body text */
  --teal-dark: #0F6B60;    /* hover state */
  --line: rgba(64, 83, 77, 0.14);
  --radius: 12px;
  --container: 1120px;
  --nav-h: 68px;           /* sticky header height — also the mobile menu's offset */
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 17px;
  line-height: 1.6;
  color: var(--ink);
  background: var(--cream);
}

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

a { color: var(--teal); }
a:hover { color: var(--teal-dark); }

:focus-visible {
  outline: 3px solid var(--teal);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Teal is invisible against the dark green bands; use text-gold there. */
.how :focus-visible,
.coming :focus-visible,
.footer :focus-visible {
  outline-color: var(--gold-text);
}

.container {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 24px;
}

.container-narrow { max-width: 760px; }

.section { padding: 88px 0; }
.section-alt { background: #FFFFFF; }

/* Orphan-rule companion: hyphenated brand compounds ("rubric-aligned",
   "color-coded") and other must-stay-together runs are wrapped in this
   span in the markup, since browsers will happily break after a hyphen. */
.nobr { white-space: nowrap; }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--green);
  color: #fff;
  padding: 10px 16px;
  z-index: 100;
}
.skip-link:focus { left: 0; color: #fff; }

/* ---------- Type scale ---------- */

h1, h2, h3 {
  color: var(--green);
  line-height: 1.15;
  margin: 0 0 0.5em;
  font-weight: bold;
  /* Orphan rule: no heading may strand a single word on its last line. */
  text-wrap: balance;
}

h2 {
  font-size: clamp(28px, 4vw, 40px);
  letter-spacing: -0.01em;
  max-width: 22em;
}

h3 { font-size: 21px; }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  font-weight: bold;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--teal);
  margin: 0 0 12px;
}

/* Kicker on the dark green bands (How it works, Coming soon). Muted cream,
   the same treatment as body copy there: on dark sections yellow is
   reserved for the one CTA, so nothing else competes with it. */
.eyebrow-light { color: rgba(249, 248, 244, 0.85); }

/* ---------- Buttons ---------- */

.btn {
  display: inline-block;
  font-family: inherit;
  font-size: 16px;
  font-weight: bold;
  line-height: 1;
  padding: 14px 22px;
  border-radius: 8px;
  border: 2px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.btn-lg { font-size: 18px; padding: 17px 28px; }

.btn-primary { background: var(--teal); color: #fff; }
.btn-primary:hover { background: var(--teal-dark); color: #fff; }

.btn-secondary {
  background: transparent;
  color: var(--teal);
  border-color: var(--teal);
}
.btn-secondary:hover { background: var(--teal); color: #fff; }

.btn-ghost {
  background: transparent;
  color: var(--green);
  border-color: var(--line);
}
.btn-ghost:hover { border-color: var(--green); color: var(--green); }

.btn-gold { background: var(--gold); color: var(--ink); }
.btn-gold:hover { background: #D59B20; color: var(--ink); }

/* ---------- Nav ---------- */

.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(249, 248, 244, 0.94);
  backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--line);
}

.nav-inner {
  display: flex;
  align-items: center;
  gap: 28px;
  min-height: var(--nav-h);
}

/* The header is sticky, so it floats over whatever an in-page link jumps to —
   without this, every anchor lands with its heading hidden underneath.
   Reserve exactly the header (its min-height plus the 1px bottom border) so
   the section's background seam lands flush under the header edge: any extra
   margin here shows as a band of the previous section's background, since
   adjacent sections alternate cream and white. The section's own top padding
   provides the breathing room. */
main[id],
section[id],
.cards[id],
.card[id] {
  scroll-margin-top: calc(var(--nav-h) + 1px);
}

.nav-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: bold;
  font-size: 18px;
  color: var(--green);
  text-decoration: none;
  letter-spacing: -0.01em;
}
.nav-brand img { border-radius: 8px; flex-shrink: 0; }

/* No header element ever wraps to a second line, at any width. The wordmark
   holds its line, and the logo, the CTA and the hamburger keep their size
   instead of being compressed by a row trying to fit too much. */
.nav-brand span { white-space: nowrap; }

.nav-links {
  display: flex;
  gap: 24px;
  margin-left: auto;
}

.nav-links a {
  color: var(--green);
  text-decoration: none;
  font-size: 15.5px;
  font-weight: bold;
}
.nav-links a:hover { color: var(--teal); }

.nav-cta { display: flex; align-items: center; gap: 12px; flex-shrink: 0; }

.nav-cta .btn { white-space: nowrap; }

.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  /* Keeps the full 44x44 tap target instead of being squeezed by the row. */
  flex-shrink: 0;
  padding: 10px;
  background: none;
  border: 0;
  cursor: pointer;
}
.nav-toggle span {
  display: block;
  height: 2.5px;
  background: var(--green);
  border-radius: 2px;
}

/* ---------- Hero ---------- */

.hero {
  /* Bottom padding is lighter than .section's 88px on purpose: the hero ends
     on a single small caption line, so the standard pad read as dead space
     against the band that follows. */
  padding: 112px 0 56px;
  text-align: center;
}

.hero-title {
  font-size: clamp(38px, 6.4vw, 68px);
  letter-spacing: -0.025em;
  line-height: 1.06;
  max-width: 15em;
  margin: 0 auto 24px;
}

/* The pen-underline line can't wrap, and at the 38px floor it needs ~327px:
   exactly the container content box at a 375px viewport. Below that, track
   the content box (100vw minus the container's 48px of padding) so the line
   keeps fitting instead of overflowing the page. */
@media (max-width: 374px) {
  .hero-title { font-size: clamp(30px, calc((100vw - 48px) * 0.115), 38px); }
}

.hero-sub {
  font-size: clamp(18px, 2.2vw, 21px);
  max-width: 38em;
  margin: 0 auto 36px;
}

.hero-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}

/* Confirmation line under /shop/success's download button ("We also emailed
   this download link to ..."). The Worker renders it only after the delivery
   webhook has recorded a sent email, so it never promises mail that didn't
   go out. */
.shop-emailed {
  font-size: 15px;
  color: rgba(46, 59, 54, 0.72);
  margin: 0;
}

.hero-note { font-size: 14.5px; color: rgba(46, 59, 54, 0.75); }

/* Teacher's-pen underline — the one signature element. */
.pen-underline {
  position: relative;
  white-space: nowrap;
}

.pen-underline-svg {
  position: absolute;
  left: -1%;
  bottom: -0.18em;
  width: 102%;
  height: 0.22em;
  color: var(--gold);
  overflow: visible;
}

.pen-underline-svg path {
  stroke-dasharray: 320;
  stroke-dashoffset: 320;
}

.pen-drawn .pen-underline-svg path {
  animation: draw-underline 0.9s ease-out 0.45s forwards;
}

@keyframes draw-underline {
  to { stroke-dashoffset: 0; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .pen-underline-svg path { stroke-dashoffset: 0; animation: none; }
  .pen-drawn .pen-underline-svg path { animation: none; }
  .btn { transition: none; }
}

/* Body-copy sibling of the hero's pen underline, in the marginalia orange
   rather than the hero's gold, for a couple of load-bearing phrases in running
   prose (approved 2026-08-19, /about).

   It is a background image and not the hero's absolutely-positioned SVG for one
   reason: a phrase inside a paragraph can wrap, and .pen-underline answers that
   with white-space: nowrap, which a 40-character phrase cannot afford in a
   327px column. As a background with box-decoration-break: clone, each line
   fragment draws its own stroke and nothing can overflow. Same hand-drawn path,
   same preserveAspectRatio="none" stretch, so it reads as the same pen.

   No draw-on animation here: the hero owns that gesture, and marginalia that
   animates stops being quiet. */
.pen-mark {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 24' preserveAspectRatio='none'%3E%3Cpath d='M4 14 C 60 21, 120 7, 180 13 S 280 17, 296 10' fill='none' stroke='%23E08A4F' stroke-width='3.4' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: 0 100%;
  /* Tuned against 17px/1.6 body text, where the numbers are tight: the box is
     tall enough for the wave to read as drawn rather than as a plain rule, and
     it sits in the ~7px of leading below the descenders, so it clears both the
     descenders above it and the next line below. */
  background-size: 100% 0.42em;
  padding-bottom: 0.42em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* Small margin annotation next to a section label. */
.pen-arrow {
  width: 34px;
  height: 24px;
  color: var(--orange);
  flex-shrink: 0;
}

/* ---------- Cards ---------- */

/* The home page's ".paths" section that these were written for is gone;
   .cards/.card live on in the resources and shop pages. */

.cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  margin-top: 20px;
}

/* Card headings are h2 where the card grid sits directly under the page h1
   (the shop index), so the outline has no gap. They must still read as card
   titles, so this pins them to the h3 treatment they replaced. */
.card h2 {
  font-size: 21px;
  letter-spacing: normal;
  max-width: none;
}

.card {
  position: relative;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 32px 28px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.card p { margin: 0 0 18px; flex-grow: 1; }
.card .btn { align-self: flex-start; }

.tag {
  align-self: flex-start;
  margin-bottom: 6px;
  font-size: 11.5px;
  font-weight: bold;
  letter-spacing: 0.1em;
  color: var(--green);
  background: rgba(232, 169, 35, 0.22);
  border: 1px solid var(--gold);
  border-radius: 999px;
  padding: 4px 10px;
}

/* ---------- How it works ---------- */

/* The steps subheadline is a full-width statement: unclamped from the h2
   default 22em cap and sized so the single line spans the content area
   edge to edge. The line renders 24.1px wide per font-px (measured), and
   the content box is 100vw minus 48px of container padding up to the
   container cap, where 44px fills the 1072px content width. Below the
   26px floor (viewports under ~640px) the line wraps instead. */
.steps-title {
  max-width: none;
  /* 4vw not 4.1vw: 100vw includes the scrollbar the content box doesn't,
     so the slope leaves ~15px of headroom to keep the line unwrapped. */
  font-size: clamp(26px, calc(4vw - 2.5px), 44px);
}

.steps {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px;
  list-style: none;
  margin: 36px 0 0;
  padding: 0;
}

/* The section's centrepiece, above the four steps. No autoplay: the poster
   does the inviting, and preload="none" means nothing but that poster is
   fetched until someone actually clicks. */
/* The video section sits on the dark green band, same treatment as the
   Coming Soon section: cream display text, gold kicker (set in the markup
   via .eyebrow-light), gold CTA and focus outlines. */
.how { background: var(--green); }

.how-lead { margin-top: 32px; }

.how-statement-title {
  font-size: clamp(30px, 4vw, 48px);
  font-weight: bold;
  color: var(--cream);
  letter-spacing: -0.015em;
  line-height: 1.1;
  margin: 0 0 24px;
  text-wrap: balance;
}

.how-statement { margin-bottom: 28px; }

@media (min-width: 768px) {
  .how-lead {
    display: grid;
    /* The video column is 61% of the section width (spec: ~60-62%); the
       fixed first track keeps that true at every viewport, gap included. */
    grid-template-columns: 61% minmax(0, 1fr);
    gap: 72px;
    align-items: center;
  }
  /* Video LEFT, statement RIGHT; the DOM keeps the statement first so it
     stacks above the video on mobile. */
  .how-lead .how-video { grid-column: 1; grid-row: 1; }
  .how-lead .how-statement { grid-column: 2; grid-row: 1; margin-bottom: 0; }
}

/* Desktop has room to spare, so the video takes more of it. Deliberately
   scoped to >=1024: at 768-1023 the text column is already down to 209px
   and must not shrink further. */
@media (min-width: 1024px) {
  .how-lead { grid-template-columns: 67% minmax(0, 1fr); }
}

.how-video {
  max-width: 960px;
  margin: 0 auto;
}

.how-video-frame { position: relative; }

.how-video video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  /* the frame the browser paints before the poster decodes */
  background: var(--green);
}

/* Click-to-play surface. Off by default, and it never uses a measured
   "controls zone" — the previous version reserved a bottom inset sized against
   Chrome's control bar, which covered Safari's fullscreen button on the Mac
   and, on iOS, sat over controls that float across the whole frame, so every
   native control was dead there.

   Two rules replace that guesswork:
   1. Touch input gets nothing at all. iOS draws its controls anywhere it likes
      and its native tap already plays, so an overlay can only do harm.
   2. On a mouse it exists only until playback starts, and site.js then removes
      it from the DOM for good. While the video is playing — the entire time
      the native controls matter — there is no element to cover them. */
.how-video-hit { display: none; }

@media (hover: hover) and (pointer: fine) {
  .how-video-hit {
    display: block;
    position: absolute;
    inset: 0;
    cursor: pointer;
    border-radius: var(--radius);
  }
}

/* ---------- Why Guayaba ---------- */

.benefit-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  margin-top: 36px;
}

.benefit {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px 24px;
}

.benefit-icon {
  display: block;
  width: 28px;
  height: 28px;
  color: var(--teal);
  margin-bottom: 12px;
}

.benefit h3 { font-size: 19px; margin: 0 0 8px; }

.benefit p { margin: 0; font-size: 15.5px; }

.step img {
  border-radius: 10px;
  border: 1px solid var(--line);
  margin-bottom: 16px;
}

.step h3 { font-size: 18px; display: flex; gap: 10px; align-items: baseline; }

.step-num {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--teal);
  color: #fff;
  font-size: 14px;
}

.step p { margin: 6px 0 0; font-size: 15.5px; }

/* ---------- Coming soon band ---------- */

.coming { background: var(--green); }

.coming h3 { color: var(--cream); }
.coming p { color: rgba(249, 248, 244, 0.85); }

.coming-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  margin-top: 8px;
}

/* Subtle panel so the three signups read as cards on the dark band. */
.coming-item {
  background: rgba(249, 248, 244, 0.07);
  border: 1px solid rgba(249, 248, 244, 0.14);
  border-radius: var(--radius);
  padding: 28px 24px;
  display: flex;
  flex-direction: column;
}

.coming-item h3 { font-size: 19px; }
.coming-item p { flex-grow: 1; margin-top: 0; }

.subscribe-form {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 18px;
}

.subscribe-form input[type="email"] {
  flex: 1 1 220px;
  font-family: inherit;
  font-size: 16px;
  padding: 13px 14px;
  border: 2px solid transparent;
  border-radius: 8px;
  background: var(--cream);
  color: var(--ink);
}

.subscribe-form input[type="email"]:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 1px;
}

.form-msg {
  flex-basis: 100%;
  margin: 4px 0 0;
  font-size: 15px;
  font-weight: bold;
  color: var(--gold-text);
  min-height: 1.4em;
}

.form-msg.is-error { color: #F2B8A0; }

/* ---------- Pricing ---------- */

.plans {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  margin-top: 36px;
  /* Tops align on the grid row; each card keeps its natural height
     (the Free card is deliberately the tallest). */
  align-items: start;
}

.plan {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 32px 28px;
  display: flex;
  flex-direction: column;
}

.plan-featured { border: 2px solid var(--teal); }

.plan-price {
  font-size: 40px;
  font-weight: bold;
  color: var(--green);
  letter-spacing: -0.02em;
  margin: 0 0 16px;
}

.plan-price span { font-size: 17px; font-weight: normal; letter-spacing: 0; }

.plan-subline {
  margin: -8px 0 18px;
  font-size: 14.5px;
  color: rgba(46, 59, 54, 0.75);
}


.plan ul {
  margin: 0 0 24px;
  padding: 0;
  list-style: none;
  flex-grow: 1;
}

.plan li {
  padding: 7px 0 7px 26px;
  position: relative;
  font-size: 15.5px;
}

.plan li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 13px;
  width: 14px;
  height: 8px;
  border-left: 2.5px solid var(--teal);
  border-bottom: 2.5px solid var(--teal);
  transform: rotate(-48deg);
}

/* Written after the `.plan li` rules on purpose: the example lines share
   their element but not their check marks, indent, or stretch space, and
   these overrides win the specificity ties only by coming later. */
.plan ul.plan-example {
  margin: 0 0 20px;
  padding: 0;
  flex-grow: 0;
  list-style: none;
  font-size: 13.5px;
  color: rgba(46, 59, 54, 0.75);
}

.plan-example li {
  padding: 2px 0;
  font-size: inherit;
}

.plan-example li::before { content: none; }

/* The example lines are held unbroken from 375 up, which is the approved
   rendering. Below that the longest of them ("100 students: 400
   evaluations/month") is wider than the card's content box, and since a
   grid item cannot shrink below its min-content width it would push all
   three cards past the container gutter. Under 375 they wrap instead. */
@media (max-width: 374px) {
  .plan-example .nobr { white-space: normal; }
}

.plan .btn { align-self: flex-start; }

/* Small text link under a plan's button — same weight and size as the
   .breadcrumb links, and the same flex-start alignment the button gets,
   since the card is a flex column. */
.plan-link {
  align-self: flex-start;
  margin-top: 14px;
  font-size: 14.5px;
  font-weight: bold;
  text-decoration: none;
}

.pricing-note {
  margin-top: 28px;
  font-size: 15.5px;
  color: rgba(46, 59, 54, 0.8);
}

/* ---------- FAQ ---------- */

/* The section headline stands alone (no eyebrow above it), so it carries the
   gap the eyebrow+h2 pairs elsewhere get from the h2's own bottom margin plus
   the following grid's margin-top. */
.faq h2 { margin-bottom: 34px; }

/* Category dividers inside the accordion. They reuse the site's label
   treatment (.eyebrow) rather than the 21px green h3, so they read as
   section labels instead of competing with the question summaries. */
.faq-category { margin: 40px 0 14px; }

.faq details {
  background: var(--cream);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 0 20px;
  margin-bottom: 12px;
}

.faq summary {
  cursor: pointer;
  font-weight: bold;
  color: var(--green);
  font-size: 17.5px;
  padding: 18px 0;
  list-style-position: outside;
}

.faq details[open] summary { border-bottom: 1px solid var(--line); }

.faq details p { padding: 14px 0 18px; margin: 0; }

/* Sign-off on the founder's answer. Italic and slightly muted so it reads as
   an attribution rather than one more sentence of the answer; no top padding
   so it sits directly under the paragraph it signs. */
.faq details p.faq-signature {
  padding-top: 0;
  font-style: italic;
  color: rgba(46, 59, 54, 0.72);
}

/* ---------- Footer ---------- */

.footer {
  background: var(--green);
  padding: 48px 0;
}

.footer-inner {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.footer-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--cream);
  font-weight: bold;
  font-size: 17px;
}
.footer-brand img { border-radius: 6px; }

.footer-links { display: flex; flex-wrap: wrap; gap: 24px; }

.footer-links a { color: var(--cream); text-decoration: none; font-size: 15.5px; }
.footer-links a:hover { color: var(--gold-text); }

/* Social icons sit in continuation after Privacy, mirroring the app's footer.
   Grouped so the three stay 16px apart while the group keeps the row's 24px. */
.footer-social { display: flex; align-items: center; gap: 16px; }
.footer-social a { display: inline-flex; align-items: center; color: var(--cream); }
.footer-social a:hover { color: var(--gold-text); }
.footer-social svg { display: block; }

/* The TPT logo is dark artwork, so it needs a cream chip to read against the
   green band; the chip's height matches the two glyphs beside it. */
.footer-tpt { background: var(--cream); padding: 3px 7px; border-radius: 6px; }
.footer-tpt:hover { opacity: 0.85; }
.footer-tpt img { display: block; height: 16px; width: auto; }

.footer-disclaimer {
  margin: 8px 0 0;
  font-size: 13.5px;
  color: rgba(249, 248, 244, 0.7);
  /* Wide enough for the whole legal line to sit on one line on desktop; it
     needs ~710px at this size. Narrower viewports wrap it naturally, and the
     nbsp-joined tail in the markup is what keeps "any testing organization."
     from being stranded — no text-wrap: balance, which split the line into
     two even halves and read as an orphan. */
  max-width: 56em;
}

/* ---------- Legal pages (terms.html, privacy.html) ---------- */

.legal { padding: 72px 0 96px; }

.legal h1 {
  font-size: clamp(30px, 4.5vw, 44px);
  letter-spacing: -0.015em;
}

.legal-updated {
  font-size: 15px;
  color: rgba(46, 59, 54, 0.7);
  margin: 0 0 40px;
}

.legal h2 {
  font-size: 22px;
  margin: 44px 0 12px;
}

.legal p, .legal li { max-width: 46em; }

.legal ul { padding-left: 22px; }
.legal li { margin-bottom: 8px; }

/* ---------- Resource pages (/resources/) ---------- */

.page-hero {
  padding: 72px 0 40px;
}

.page-hero h1 {
  font-size: clamp(32px, 5vw, 52px);
  letter-spacing: -0.02em;
  max-width: 18em;
  margin: 0 0 16px;
}

.page-hero .lead {
  font-size: clamp(17px, 2vw, 19.5px);
  max-width: 42em;
  margin: 0 0 8px;
}

.page-hero h2 { font-size: 24px; margin-top: 28px; }
.page-hero ol, .page-hero ul { max-width: 42em; padding-left: 22px; }
.page-hero li { margin-bottom: 8px; }

.breadcrumb {
  font-size: 14.5px;
  font-weight: bold;
  text-decoration: none;
  display: block;
  width: fit-content;
  margin-bottom: 20px;
}

/* Interactive tool panel */

.tool {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 32px 28px;
  max-width: 860px;
}

.tool label { font-weight: bold; font-size: 15.5px; }

.tool input[type="text"],
.tool textarea {
  width: 100%;
  font-family: inherit;
  font-size: 16px;
  padding: 13px 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--cream);
  color: var(--ink);
  margin-top: 8px;
}

.tool textarea { resize: vertical; }

.tool input[type="file"] { margin-top: 8px; font-size: 15px; }

.tool-field { margin-bottom: 18px; }

.tool-status {
  margin: 14px 0 0;
  font-size: 15.5px;
  font-weight: bold;
  color: var(--orange-text);
  min-height: 1.4em;
}

.tool-output-wrap { margin-top: 24px; display: none; }

.tool-output-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.tool-output {
  margin-top: 12px;
  padding: 24px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--cream);
  font-size: 16.5px;
  line-height: 1.6;
}

.tool-output > *:first-child { margin-top: 0; }
.tool-output h1 { font-size: 24px; margin: 24px 0 10px; }
.tool-output h2 { font-size: 20px; color: var(--teal); margin: 20px 0 8px; }
.tool-output h3 { font-size: 18px; margin: 16px 0 6px; }
.tool-output p { margin: 0 0 12px; }
.tool-output ul, .tool-output ol { margin: 0 0 12px; padding-left: 26px; }

/* Embedded documents & slides */

.doc-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
  margin-top: 36px;
}

.doc-grid-2 { grid-template-columns: repeat(2, 1fr); max-width: 860px; }

.doc-embed { margin: 0; }

.doc-embed .doc-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: #fff;
}

.doc-embed iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.doc-embed figcaption {
  text-align: center;
  margin-top: 12px;
  font-weight: bold;
  font-size: 15.5px;
  color: var(--green);
}

.slides-embed .doc-frame { aspect-ratio: 16 / 10.5; }

.resource-section { padding: 48px 0 88px; }

@media (max-width: 900px) {
  .doc-grid, .doc-grid-2 { grid-template-columns: 1fr; }
}

/* ---------- Shop (/shop/) ---------- */

.shop-hero { padding: 72px 0 16px; }

/* Price + button as one block anchored to the card's bottom edge, so all
   three shop cards line up on the same row regardless of description length. */
.card-buy {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.card-buy .price-tag { margin: 0; }

.product { padding: 48px 0 88px; }

.product-top {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: 48px;
  align-items: start;
}

.product-top img {
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.price-tag {
  font-size: 32px;
  font-weight: bold;
  color: var(--green);
  margin: 8px 0 4px;
}

.price-note { font-size: 14.5px; color: rgba(46, 59, 54, 0.75); margin: 0 0 20px; }

.product-body { max-width: 46em; margin-top: 44px; }
.product-body h2 { font-size: 22px; margin: 36px 0 10px; }
.product-body ul { padding-left: 22px; }
.product-body li { margin-bottom: 8px; }

.product-gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  margin-top: 44px;
}

.product-gallery img {
  border: 1px solid var(--line);
  border-radius: 10px;
}

.buy-btn[disabled] {
  opacity: 0.55;
  cursor: not-allowed;
}

/* Study Abroad free kit form — light-background twin of .subscribe-form:
   same flex-row input+button shape, but .contact-form's white-input colors,
   since this page has no dark section to borrow gold-on-green from. */
.free-kit-form {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 4px;
}

.free-kit-form input[type="email"] {
  flex: 1 1 220px;
  font-family: inherit;
  font-size: 16px;
  padding: 13px 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  color: var(--ink);
}

.free-kit-form input[type="email"]:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 1px;
}

.free-kit-msg {
  flex-basis: 100%;
  margin: 4px 0 0;
  font-size: 15px;
  font-weight: bold;
  color: var(--orange-text);
  min-height: 1.4em;
}

.free-kit-msg.is-error { color: #A6392A; }

.free-kit-note { margin-top: 10px; }

.free-kit-social { margin-top: 22px; }

.free-kit-success p { margin: 0 0 10px; }

/* Product image lightbox (built by js/shop.js). No entrance animation —
   instant open/close needs no prefers-reduced-motion guard.

   .lightbox-figure and the three control buttons are DOM siblings, both
   position: absolute with no explicit z-index — without one, stacking falls
   back to DOM order, and the figure (inset: 0, painted last) sat on top of
   the buttons. It has no visible background there, so the buttons stayed
   visible, but the figure silently ate every click aimed at them. Explicit
   z-index pins the controls above the figure regardless of markup order. */

.lightbox-trigger {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
}

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: none;
  background: rgba(46, 59, 54, 0.92);
}

.lightbox.is-open { display: block; }

.lightbox-figure {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 72px 24px;
  margin: 0;
}

.lightbox-figure img {
  max-width: min(92vw, 1100px);
  max-height: 74vh;
  border-radius: 8px;
  cursor: zoom-in;
}

/* Zoomed state: the figure becomes the scroll container (native drag/swipe
   panning) and the image renders at its explicit pixel size instead of
   being fit-constrained. Flex centering is dropped here on purpose — a
   flex-centered scroll container can't reach the start of an overflowing
   child (a well-known flexbox+overflow quirk), so block layout is what
   makes every edge of a zoomed image reachable by scroll. */
.lightbox-figure.is-zoomed {
  display: block;
  overflow: auto;
  padding: 0;
  cursor: grab;
}

.lightbox-figure.is-zoomed:active { cursor: grabbing; }

.lightbox-figure.is-zoomed img {
  max-width: none;
  max-height: none;
  border-radius: 0;
  display: block;
  margin: 0 auto;
  /* The zoom runs in steps, so the cursor advertises which one is next:
     zoom-in while there is more magnification left, zoom-out on the last
     step, where the next click returns to fit. */
  cursor: zoom-in;
}

.lightbox-figure.is-zoomed.is-max-zoom img { cursor: zoom-out; }

/* An image with no useful zoom left (it opens at or past its own
   resolution) is view-only: no zoom cursor, since clicking does nothing. */
.lightbox-figure.is-view-only img { cursor: default; }

.lightbox-figure.is-zoomed .lightbox-caption { display: none; }

.lightbox-caption {
  color: var(--cream);
  font-size: 14.5px;
  text-align: center;
  max-width: 90%;
  margin: 0;
}

/* Fixed, not absolute: these must stay put in the viewport no matter how far
   the zoomed image is panned inside the scrolling figure beneath them. The
   close X in particular is the guaranteed exit when a zoomed image covers
   the whole viewport and there is no backdrop left to click. */
.lightbox-close,
.lightbox-prev,
.lightbox-next {
  position: fixed;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 2px solid transparent;
  border-radius: 50%;
  background: rgba(249, 248, 244, 0.14);
  color: var(--cream);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}

.lightbox-close:hover, .lightbox-prev:hover, .lightbox-next:hover {
  background: rgba(249, 248, 244, 0.28);
}

/* Teal focus rings are invisible against this dark overlay — same fix as
   the coming-soon band and footer. */
.lightbox :focus-visible { outline-color: var(--gold-text); }

.lightbox-close { top: 16px; right: 16px; }
.lightbox-prev { left: 16px; top: 50%; transform: translateY(-50%); }
.lightbox-next { right: 16px; top: 50%; transform: translateY(-50%); }

@media (max-width: 640px) {
  .lightbox-figure { padding: 64px 16px; }
  .lightbox-prev, .lightbox-next { width: 40px; height: 40px; font-size: 18px; }
}

.card .card-img {
  border: 1px solid var(--line);
  border-radius: 10px;
  margin-bottom: 14px;
}

@media (max-width: 900px) {
  .product-top { grid-template-columns: 1fr; }
  .product-gallery { grid-template-columns: 1fr 1fr; }
}

/* ---------- Responsive ---------- */

@media (max-width: 900px) {
  .cards, .plans { grid-template-columns: 1fr; }
  .steps { grid-template-columns: 1fr 1fr; }
  .coming-grid { grid-template-columns: 1fr; gap: 24px; }
  .section { padding: 64px 0; }
}

/* Compact header. Measured: the desktop row needs 963px of viewport to hold
   the wordmark, the seven nav labels and the CTA on one line, and below that
   they wrap. So the hamburger covers everything under 1019, where the row
   first has real slack (56px) instead of the 0px it has at 963. The menu's
   own contents are unchanged.

   The number tracks the label widths, not the label count. It was 968/1024
   with six labels, then 1037/1092 when About joined (2026-08-19). The
   2026-08-20 renames shortened three labels — Essay Evaluator to Essay
   Grader, Free Tools to Free, Curricula to Sign Up — giving back 74px, so it
   came down to 963/1019. Same rule, same 56px of slack — re-measure and move
   it again if the menu ever changes. */
@media (max-width: 1018px) {
  .nav-toggle { display: flex; }

  /* The desktop row is right-aligned by .nav-links' auto margin, but that
     element is out of flow here, so the CTA and hamburger need their own.
     Without it they float in mid-row wherever the wordmark leaves them. */
  .nav-cta { margin-left: auto; }

  .nav-links {
    display: none;
    position: absolute;
    top: var(--nav-h);
    left: 0;
    right: 0;
    flex-direction: column;
    gap: 0;
    background: var(--cream);
    border-bottom: 1px solid var(--line);
    padding: 8px 24px 16px;
  }

  .nav-links.is-open { display: flex; }
  .nav-links a { padding: 12px 0; }
}

/* Phone header: wordmark + hamburger only. The wordmark, the CTA and the
   hamburger together need ~433px inside a 327px content box at 375, and no
   header element may wrap, so the CTA is the one that gives way here. It is
   the first thing in the hero immediately below. */
@media (max-width: 720px) {
  .nav-cta .btn { display: none; }

  /* Only bites at the very narrow end, where wordmark plus hamburger would
     otherwise overrun the container gutter; everywhere else the auto margin
     sets the spacing and this gap is never seen. */
  .nav-inner { gap: 12px; }

  .benefit-grid { grid-template-columns: 1fr; }

  .hero { padding: 72px 0 64px; }
  .steps { grid-template-columns: 1fr; }
}

/* ---------- For Schools & Districts (/schools) ---------- */

/* The hero here is left-aligned prose, not the home page's centred stack,
   so the CTA gets its own wrapper rather than .hero-actions' centring. */
.schools-cta { margin: 28px 0 0; }

/* These steps are sentences, not screenshots, so they stack in one column
   instead of the four-across grid .steps uses on the home page. The number
   is a sibling of the paragraph here (not inside a heading), which is what
   lets the text hang in a single column beside it. */
.steps-stack {
  display: grid;
  gap: 20px;
  max-width: 46em;
  margin: 28px 0 0;
  padding: 0;
  list-style: none;
}

.steps-stack .step { display: flex; gap: 14px; align-items: flex-start; }
.steps-stack .step-num { margin-top: 2px; }
.steps-stack .step p { margin: 0; font-size: 16.5px; }

/* Vendor identity for a business office: name, city and state, email, W-9.
   No street address anywhere on the site. */
.vendor-lead {
  margin: -8px 0 0;
  font-size: 15.5px;
  color: rgba(46, 59, 54, 0.75);
}

.vendor-card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px 24px;
  margin: 24px 0 0;
  max-width: 34em;
}

.vendor-card p { margin: 0 0 6px; font-size: 16.5px; }
.vendor-card p:last-child { margin-bottom: 0; }
.vendor-name { font-weight: bold; color: var(--green); }

.vendor-note {
  max-width: 46em;
  margin: 20px 0 0;
  font-size: 15.5px;
  color: rgba(46, 59, 54, 0.8);
}

/* ---------- About (/about) ---------- */

/* Portrait floated into the top right of the bio, text to its left, rather than
   the two sitting in their own grid columns. As a column the photo was 500px
   tall against ~900px of prose, so the layout ended in 400px of nothing beside
   the lower two thirds of the text; floated, the prose closes over that space
   and the whole section gets shorter (2026-08-19).

   flow-root, not a clearfix: it contains the float so the section below starts
   where the content ends. .about-bio must NOT get a block formatting context of
   its own (no overflow, no flow-root) — that would sit it beside the float
   instead of letting its line boxes wrap around it, which is the whole point. */
.about-grid {
  display: flow-root;
  margin-top: 8px;
}

/* The 4:5 box is declared rather than left to the image, so the column holds
   its shape while the photo decodes and a future replacement at the same path
   cannot reflow the page. */
.about-photo {
  background: #E4E2DD;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  aspect-ratio: 4 / 5;
  width: 240px;
  max-width: 100%;
  margin: 0 0 28px;
}

/* Below the wrap breakpoint the float would leave a text column too narrow to
   read, so the portrait goes back to sitting above the bio — and stays small
   there, since at full column width its 4:5 box would push the headline most of
   a phone screen down before a single word of the bio is read. */
@media (min-width: 860px) {
  .about-photo {
    float: right;
    /* Proportional up to the 400px cap rather than a flat 400: at a flat width
       the text beside the float is down to 46 characters a line right at this
       breakpoint, and only reaches a comfortable measure near 1100px. */
    width: min(38%, 400px);
    margin: 6px 0 24px 44px;
  }
}

.about-photo img { width: 100%; height: 100%; object-fit: cover; }

.about-bio h1 { margin-bottom: 20px; }

/* 46em, the same measure terms.html and privacy.html use for running prose
   (see .legal p). It was briefly uncapped so the lines clearing the float would
   reach the right margin; at 1280 that ran them to ~130 characters, about double
   a comfortable measure, so the cap is back (2026-08-20). The lines beside the
   photo are narrower still — the float constrains them — and that is fine: this
   cap is about the ones underneath it. */
.about-bio p { max-width: 46em; margin: 0 0 18px; }
.about-bio p:last-child { margin-bottom: 0; }

/* ---------- Reviews ---------- */

.quotes-lead {
  max-width: 42em;
  margin: -4px 0 0;
  font-size: 16.5px;
  color: rgba(46, 59, 54, 0.8);
}

.quotes {
  display: grid;
  gap: 24px;
  margin-top: 28px;
  /* Each card keeps its natural height; the short third one must never be
     stretched to match a tall neighbour. */
  align-items: start;
}

/* Two columns, with the long review holding the left on its own and the two
   shorter ones stacked down the right. Explicit placement rather than letting
   the grid flow them: in source order the third card would land bottom-left and
   leave a hole beside it, and spanning it across both columns (what it did
   before 2026-08-19) made a two-line quote read as a centred pull quote rather
   than as a third review. All three tops now line up on a column edge. */
@media (min-width: 860px) {
  .quotes { grid-template-columns: 1fr 1fr; }
  .quotes > :nth-child(1) { grid-column: 1; grid-row: 1 / span 2; }
  .quotes > :nth-child(2) { grid-column: 2; grid-row: 1; }
  .quotes > :nth-child(3) { grid-column: 2; grid-row: 2; }
}

.quote-card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 30px 28px;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.quote-card blockquote { margin: 0; }
.quote-card blockquote p { margin: 0; max-width: 42em; }

/* Pinned to the bottom of the card so the rules line up across a row even
   when one quote is much longer than its neighbour. */
.quote-meta {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: auto;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}

.quote-title {
  font-weight: bold;
  color: var(--green);
  font-size: 15.5px;
}

/* Stars, then product and date. Two flex children only, and the second is a
   plain text run rather than more flex items: a full row needs ~355px and the
   card's content box is 271px at 375 and 338px at 860, so it has to wrap. With
   the product and date as running text, greedy line filling breaks at the space
   AFTER the separator, which leaves the middot at the end of a line instead of
   stranded at the start of the next one. That is also why there is no separator
   between the stars and the product: one there would begin the wrapped line. */
.quote-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  font-size: 14.5px;
  color: rgba(46, 59, 54, 0.75);
}

.quote-date { white-space: nowrap; }

.stars { color: var(--gold); fill: currentColor; flex-shrink: 0; }

.quote-sep { color: rgba(46, 59, 54, 0.45); }

/* ---------- Contact form ---------- */

.contact-grid {
  display: grid;
  gap: 32px;
  margin-top: 28px;
  align-items: start;
}

@media (min-width: 860px) {
  .contact-grid { grid-template-columns: minmax(0, 1fr) 360px; gap: 56px; }
}

.contact-form { max-width: 34em; }

.contact-form .field { margin-bottom: 18px; }

.contact-form label {
  display: block;
  font-weight: bold;
  font-size: 15.5px;
  color: var(--green);
}

.contact-form input[type="text"],
.contact-form input[type="email"],
.contact-form textarea {
  width: 100%;
  font-family: inherit;
  font-size: 16px;
  padding: 13px 14px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: #fff;
  color: var(--ink);
  margin-top: 8px;
}

.contact-form textarea { resize: vertical; }

/* Bot bait: off-screen, out of the tab order, hidden from assistive tech.
   Not display:none — some bots skip those and fill everything else. */
.honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.contact-msg {
  margin: 14px 0 0;
  font-size: 15.5px;
  font-weight: bold;
  color: var(--orange-text);
  min-height: 1.4em;
}

.contact-msg.is-error { color: #A6392A; }

/* Sized up well past body copy (2026-08-19): the form is tall and this column
   is short, so at 16.5px it read as a caption stranded in a large empty field.
   It is the only place on the site running larger than the hero's lead, which
   is what makes it hold the column on its own. */
.contact-aside p {
  margin: 0 0 18px;
  font-size: clamp(20px, 2.2vw, 28px);
  line-height: 1.3;
  color: var(--green);
}

.contact-aside .contact-email {
  font-size: clamp(17px, 1.5vw, 19px);
  font-weight: bold;
  line-height: 1.4;
}
