/* ==========================================================================
   Ycotes — component library.
   Every value comes from tokens.css. No raw hex below this line: if a colour
   is needed that isn't a token, the token set is wrong, not this file.
   Mobile-first. No framework.
   ========================================================================== */

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

html { -webkit-text-size-adjust: 100%; scroll-padding-top: 5.5rem; }

body {
  margin: 0;
  background: var(--surface-0);
  color: var(--text-mid);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  /* Belt and braces against the horizontal scroll that parallax can cause. */
  overflow-x: hidden;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  color: var(--text-hi);
  line-height: var(--lh-snug);
  margin: 0 0 var(--s-4);
  font-weight: 500;              /* large + calm beats medium + shouting */
  text-wrap: balance;
}
h1 { font-size: var(--fs-hero); line-height: var(--lh-tight); letter-spacing: var(--tracking-hero); }
h2 { font-size: var(--fs-h2);  letter-spacing: -0.02em; }
h3 { font-size: var(--fs-h3);  letter-spacing: -0.01em; }

p { margin: 0 0 var(--s-4); max-width: var(--measure); text-wrap: pretty; }

a { color: inherit; text-decoration-color: color-mix(in srgb, var(--y-yellow) 55%, transparent);
    text-underline-offset: 0.2em; transition: color var(--dur-fast) var(--ease-out); }
a:hover { color: var(--accent-ink); }

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

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

/* The [hidden] attribute loses to any class that sets `display`. Without this
   both nav panels render at once. Must sit above the component rules. */
[hidden] { display: none !important; }

/* Honeypot. Lived in contact.css, which meant the "Website" trap field was
   plainly VISIBLE on the register form — the one place a bot signup actually
   costs you. Global now, so every form gets it.
   Positioned off-screen rather than display:none, which some bots detect. */
.hp {
  position: absolute !important; left: -9999px !important;
  width: 1px; height: 1px; overflow: hidden;
}

/* --- Utilities -------------------------------------------------------- */
.u-sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: var(--s-4); top: -100px; z-index: var(--z-modal);
  background: var(--y-yellow); color: var(--y-black);
  padding: var(--s-3) var(--s-6); border-radius: var(--radius);
  font-weight: 600; transition: top var(--dur) var(--ease-out);
}
.skip-link:focus { top: var(--s-4); }

.container {
  width: 100%; max-width: var(--container);
  margin-inline: auto; padding-inline: var(--gutter);
}
.container--wide { max-width: var(--container-wide); }

.section { padding-block: var(--section-y); position: relative; }

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--accent-ink);
  margin: 0 0 var(--s-3);
}

.section__head { margin-bottom: var(--s-12); }
.section__title { max-width: 20ch; }
.section__sub { font-size: var(--fs-body-lg); color: var(--text-mid); max-width: 56ch; }

/* Accent — the one yellow word in a heading. Yellow as light, not as fill. */
.accent { color: var(--accent-ink); }

/* An alternating band. Two identical grounds in a row make a long page read as
   one undifferentiated scroll; this is the cheapest way to break it. */
.section--alt { background: var(--surface-1); border-block: 1px solid var(--surface-line); }
.section__foot { margin-top: var(--s-8); display: flex; flex-wrap: wrap; gap: var(--s-3); }

/* --- Hero -------------------------------------------------------------
   Shared by every top-of-page hero on the site. Home and the business pages
   differ in content, not in shell. */
.hero {
  position: relative;
  padding-block: clamp(4rem, 2rem + 10vw, 9rem) clamp(3rem, 2rem + 5vw, 6rem);
  overflow: hidden;
}

/* Yellow as a LIGHT SOURCE, not as a fill. A soft radial bloom behind the
   headline reads premium; a flat yellow panel reads budget. */
.hero__glow {
  position: absolute; top: -30%; left: 50%;
  width: min(120vw, 1100px); aspect-ratio: 1;
  transform: translateX(-50%);
  background: radial-gradient(circle at 50% 50%,
              color-mix(in srgb, var(--y-yellow) 26%, transparent) 0%,
              transparent 62%);
  pointer-events: none;
  will-change: transform;
}

.hero__inner { position: relative; }
.hero h1 { max-width: 18ch; margin-bottom: var(--s-6); }
.hero__sub {
  font-size: var(--fs-body-lg); color: var(--text-mid);
  max-width: 56ch; margin-bottom: var(--s-8);
}
.hero__cta { display: flex; flex-wrap: wrap; gap: var(--s-3); }
.hero__note { margin-top: var(--s-6); font-size: var(--fs-sm); color: var(--text-lo); }

/* Sub-pages sit under a breadcrumb and carry less air than the homepage. */
.hero--sub { padding-block: clamp(2.5rem, 1.5rem + 6vw, 5.5rem) clamp(2rem, 1.5rem + 4vw, 4rem); }

/* A hero's bottom padding and the next section's top padding stack, which on a
   wide screen adds up to ~10rem of dead space between a headline and the thing
   it introduces. The first section after a sub-hero collapses its own top
   padding — the hero has already provided the breathing room. */
.hero--sub + .section,
.hero--sub + .auth-wrap,
.hero--sub + section > .container > .legal { padding-top: var(--s-4); }
.hero--sub + .section--tight { padding-top: var(--s-2); }
.hero--sub h1 { max-width: 20ch; }
.hero__crumbs { margin-bottom: var(--s-6); }

/* Scaler's gradient sweep. Five stops is what makes the loop seamless. */
.sweep {
  background: linear-gradient(90deg,
    var(--y-yellow) 0%, var(--y-red) 25%, var(--y-yellow) 50%,
    var(--y-yellow-soft) 75%, var(--y-yellow) 100%);
  background-size: 200% auto;
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}

/* --- Buttons ---------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
  padding: var(--s-3) var(--s-6);
  border: 1px solid transparent; border-radius: var(--radius-pill);
  font-family: var(--font-body); font-size: var(--fs-body); font-weight: 600;
  line-height: 1; text-decoration: none; cursor: pointer; white-space: nowrap;
  transition: transform var(--dur-fast) var(--ease-spring),
              background-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur) var(--ease-out);
}
.btn:active { transform: translateY(1px); }

/* A pill with `white-space: nowrap` and a long label is wider than a phone —
   "Pick a ready avatar from Ycotes Studio instead" measured 402px inside a
   390px viewport and put a horizontal scrollbar on the whole document. Buttons
   stay single-line wherever they fit; below that they are allowed to wrap and
   are capped at the container. Nothing changes on any screen where the label
   already fit. */
@media (max-width: 30rem) {
  .btn { white-space: normal; max-width: 100%; text-align: center; line-height: 1.25; }
}

/* Red is reserved for action. If it isn't a CTA, it isn't red. */
.btn--primary { background: var(--y-red); color: var(--y-white); }
.btn--primary:hover { background: var(--y-red-700); color: var(--y-white); box-shadow: var(--glow-red); }

.btn--secondary { background: var(--y-yellow); color: var(--y-black); }
.btn--secondary:hover { background: var(--y-yellow-300); color: var(--y-black); box-shadow: var(--glow-yellow); }

.btn--ghost { background: transparent; color: var(--text-hi); border-color: var(--surface-line); }
.btn--ghost:hover { border-color: var(--y-yellow); color: var(--accent-ink); background: var(--surface-1); }

.btn--sm { padding: var(--s-2) var(--s-4); font-size: var(--fs-sm); }
.btn--lg { padding: var(--s-4) var(--s-8); font-size: var(--fs-body-lg); }

/* --- Nav -------------------------------------------------------------- */
.nav {
  position: sticky; top: 0; z-index: var(--z-nav);
  background: color-mix(in srgb, var(--surface-0) 82%, transparent);
  backdrop-filter: saturate(150%) blur(14px);
  border-bottom: 1px solid var(--surface-line);
}
.nav__inner {
  display: flex; align-items: center;
  min-height: 4.5rem;

  /* THE BAR IS NOT AN ARTICLE. `.container` caps its children at 1200px,
     which is the right measure for prose and the wrong one for a full-bleed
     sticky bar: the full student nav — brand + the two door pills + seven
     links + search + theme + Log in + Join free — needs about 1305px, so it
     overflowed its rail at EVERY viewport and "Join free" was clipped by the
     window edge even on a 1470px screen. The bar spans the whole width
     already; its contents may use it. */
  max-width: var(--container-wide);

  /* Fluid, because this is the gap that gives way first when the bar is
     tight — three of them sit between four groups that cannot themselves
     shrink below their text. */
  gap: clamp(0.9rem, 1.4vw, 1.5rem);
}
.nav__brand {
  display: inline-flex; align-items: center; gap: var(--s-2);
  text-decoration: none; flex: 0 0 auto;
}
.nav__mark { border-radius: var(--radius-sm); }
.nav__wordmark {
  font-family: var(--font-display); font-size: 1.25rem; font-weight: 600;
  color: var(--text-hi); letter-spacing: -0.02em;
}

.door-switch {
  position: relative; display: none;
  padding: 3px; gap: 2px;
  background: var(--surface-1); border: 1px solid var(--surface-line);
  border-radius: var(--radius-pill);
}
.door-switch__btn {
  position: relative; z-index: 1;
  padding: var(--s-2) var(--s-4);
  background: none; border: 0; cursor: pointer; text-decoration: none;
  font-family: var(--font-body); font-size: var(--fs-sm); font-weight: 600;
  color: var(--text-lo); border-radius: var(--radius-pill); white-space: nowrap;
  transition: color var(--dur-fast) var(--ease-out);
}
.door-switch__btn:hover { color: var(--text-hi); }
.door-switch__btn[aria-current="page"] { color: var(--y-black); }
.door-switch__btn[aria-current="page"]:hover { color: var(--y-black); }
.door-switch__thumb {
  position: absolute; z-index: 0; top: 3px; bottom: 3px; left: 3px;
  width: calc(50% - 3px);
  background: var(--y-yellow); border-radius: var(--radius-pill);
  transition: transform var(--dur) var(--ease-out);
}
html[data-door="business"] .door-switch__thumb { transform: translateX(100%); }

.nav__links { display: none; margin-inline-start: auto; }
/* Seven links x a fixed 24px gap is 144px of air in a bar that has none to
   spare. Fluid: full at desk width, tighter as the bar closes in. */
.nav__list { display: flex; gap: clamp(0.85rem, 1.15vw, 1.5rem); align-items: center; }
.nav__list a {
  font-size: var(--fs-sm); font-weight: 500; color: var(--text-mid);
  text-decoration: none; position: relative; padding-block: var(--s-2);
}
.nav__list a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--y-yellow); transform: scaleX(0); transform-origin: left;
  transition: transform var(--dur) var(--ease-out);
}
.nav__list a:hover { color: var(--text-hi); }
.nav__list a:hover::after { transform: scaleX(1); }

.nav__actions { display: none; gap: var(--s-2); margin-inline-start: var(--s-4); }

.nav__burger {
  margin-inline-start: auto;
  display: flex; flex-direction: column; justify-content: center; gap: 5px;
  width: 44px; height: 44px; padding: 0 10px;
  background: none; border: 0; cursor: pointer;
}
.nav__burger span {
  display: block; height: 2px; background: var(--text-hi); border-radius: 2px;
  transition: transform var(--dur) var(--ease-out), opacity var(--dur-fast) linear;
}

/* ── THE THREE TIERS OF THE BAR ────────────────────────────────────────────
   One breakpoint used to do this: below 62rem everything collapsed into the
   burger, above it everything appeared at once. But "everything" does not fit
   at 62rem — it needs more than 1300px — so between 992px and ~1300px the bar
   silently overflowed to the right and took the primary CTA off the screen.

   What gives way, and in which order, is a judgement about what the bar is
   for. The door switch and "Join free" are what the business needs a visitor
   to see; the seven section links are the most numerous and the least urgent,
   and every one of them is in the sheet the burger opens. So the links go
   first and the CTA goes last.

     < 64rem   burger only — the phone bar
     64-81rem  door switch + actions + burger (links live in the sheet)
     >= 81rem  + the section links
     >= 88rem  + the labelled "Search ⌘K" pill instead of the icon        */

@media (min-width: 64rem) {
  .door-switch, .nav__actions { display: flex; }
  /* With .nav__links hidden its `margin-inline-start: auto` goes with it, and
     without a replacement the actions bunch up against the door switch in the
     middle of the bar. */
  .nav__actions { margin-inline-start: auto; }
  /* ONE auto margin, not two. The burger carries its own `auto` for the phone
     bar, where it is the only thing on the right. Here the actions have taken
     that job, and two auto margins SPLIT the free space between them — the
     actions stopped 144px short of the burger and sat marooned in the middle
     of the bar with a gap on either side. */
  .nav__burger { margin-inline-start: var(--s-2); }
}

@media (min-width: 81rem) {
  .nav__links { display: flex; }
  .nav__burger { display: none; }
  /* The links take the spacer back, so the actions sit tight beside them. */
  .nav__actions { margin-inline-start: var(--s-4); }
}

/* --- Mobile menu ------------------------------------------------------ */
.mobile-menu {
  position: fixed; inset: 0; z-index: var(--z-modal);
  background: var(--surface-0);
  overflow-y: auto; overscroll-behavior: contain;
}
.mobile-menu[hidden] { display: none; }
.mobile-menu__top {
  display: flex; align-items: center; justify-content: space-between;
  min-height: 4.5rem; border-bottom: 1px solid var(--surface-line);
}
.mobile-menu__close {
  width: 44px; height: 44px; font-size: 2rem; line-height: 1;
  background: none; border: 0; color: var(--text-hi); cursor: pointer;
}
.mobile-menu__body { padding-block: var(--s-8) var(--s-16); }
.mobile-menu__list { margin-bottom: var(--s-8); }
.mobile-menu__list a {
  display: flex; flex-direction: column; gap: 2px;
  padding: var(--s-3) 0; border-bottom: 1px solid var(--surface-line);
  text-decoration: none;
}
.mobile-menu__list span { font-size: var(--fs-h3); color: var(--text-hi); font-family: var(--font-display); }
.mobile-menu__list small { font-size: var(--fs-sm); color: var(--text-lo); }
.mobile-menu__actions { display: flex; gap: var(--s-3); margin-top: var(--s-8); }
.mobile-menu__actions .btn { flex: 1; }

body.menu-open { overflow: hidden; }

/* --- Cards ------------------------------------------------------------ */
.card {
  background: var(--surface-1);
  border: 1px solid var(--surface-line);
  border-radius: var(--radius-lg);
  padding: var(--s-6);
  box-shadow: var(--shadow-card);
  transition: transform var(--dur) var(--ease-out),
              border-color var(--dur) var(--ease-out),
              box-shadow var(--dur) var(--ease-out);
}
.card:hover {
  transform: translateY(-3px);
  border-color: color-mix(in srgb, var(--y-yellow) 40%, var(--surface-line));
  box-shadow: var(--glow-yellow);
}
.card__title { font-size: var(--fs-h3); margin-bottom: var(--s-2); }
.card__body  { color: var(--text-mid); margin: 0; }
.card__link {
  display: inline-block; margin-top: var(--s-4);
  font-size: var(--fs-sm); font-weight: 600;
  color: var(--accent-ink); text-decoration: none;
}
.card__link:hover { text-decoration: underline; text-underline-offset: 0.25em; }

/* --- Grids. Deliberately several, so consecutive sections can differ. --- */
/* minmax(0, 1fr), NEVER bare 1fr. A bare `1fr` is `minmax(auto, 1fr)`: the
   track refuses to shrink below its widest unbreakable content, so one long
   subject name or course title pushed a column past the screen edge — the
   /subjects/, /quiz/ and course pages all scrolled sideways on phones and
   tablets because of it (found by the width sweep, 2026-09-25). */
.grid { display: grid; gap: var(--s-6); }
.grid > * { min-width: 0; }
.grid--2 { grid-template-columns: minmax(0, 1fr); }
.grid--3 { grid-template-columns: minmax(0, 1fr); }
.grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* The 7/5 asymmetric split. Symmetry is what makes a two-up read as a
   comparison table rather than a designed layout. */
.grid--75 { grid-template-columns: minmax(0, 1fr); }

@media (min-width: 48rem) {
  .grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Two across on a tablet, three from a laptop up: three 230px columns in
     portrait-tablet width left every card a cramped tower of wrapped words. */
  .grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .grid--75 { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--s-12); }
}
@media (min-width: 64rem) {
  .grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 30rem) {
  /* Four tiny columns-of-two on a 320px phone crush their content; one column reads. */
  .grid--4 { grid-template-columns: minmax(0, 1fr); gap: var(--s-4); }
}
/* Long words (URLs, subject codes, "Engineering-Mathematics-III") wrap
   instead of widening their card. */
.card, .card * { overflow-wrap: anywhere; }

/* --- Stats ------------------------------------------------------------ */
.stats { display: flex; flex-wrap: wrap; gap: var(--s-8) var(--s-12); }
.stat__num {
  font-family: var(--font-display); font-size: var(--fs-h2);
  color: var(--text-hi); line-height: 1; letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.stat__label { font-size: var(--fs-sm); color: var(--text-lo); margin: var(--s-2) 0 0; }

/* --- Table (the capability inventory) --------------------------------- */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table { width: 100%; border-collapse: collapse; min-width: 44rem; }
.table th, .table td {
  text-align: left; padding: var(--s-4);
  border-bottom: 1px solid var(--surface-line); font-size: var(--fs-sm);
}
.table th {
  font-family: var(--font-mono); font-size: var(--fs-xs);
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  color: var(--text-lo); font-weight: 500;
}
.table td:first-child { color: var(--text-hi); font-weight: 600; }
.table tbody tr { transition: background-color var(--dur-fast) var(--ease-out); }
.table tbody tr:hover { background: var(--surface-1); }

/* --- Forms ------------------------------------------------------------ */
.input {
  width: 100%; padding: var(--s-3) var(--s-4);
  background: var(--surface-2); color: var(--text-hi);
  border: 1px solid var(--surface-line); border-radius: var(--radius);
  font-family: inherit; font-size: var(--fs-body);
  transition: border-color var(--dur-fast) var(--ease-out);
}
.input::placeholder { color: var(--text-lo); }
.input:focus { border-color: var(--y-yellow); outline: none; }

/* --- Forms (shared: contact, login, register, newsletter) -------------- */
.form__row { margin-bottom: var(--s-5); }
/* auto-fit responds to the CONTAINER, not the viewport. A media query at 40rem
   never fired inside a 34rem card, so paired fields stayed stacked on a wide
   screen — the field pairing silently did nothing. */
.form__grid {
  display: grid; gap: var(--s-5);
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}

.form__label {
  display: block; margin-bottom: var(--s-2);
  font-size: var(--fs-sm); font-weight: 600; color: var(--text-hi);
}
.form__opt { font-weight: 400; color: var(--text-lo); }
.form__err { margin: var(--s-2) 0 0; font-size: var(--fs-sm); color: var(--y-red); }
.form__note { margin-top: var(--s-4); font-size: var(--fs-sm); color: var(--text-lo); }
.form__note a { color: var(--accent-ink); }

textarea.input { resize: vertical; min-height: 8rem; font-family: inherit; }
.input[aria-invalid="true"] { border-color: var(--y-red); }



/* --- Badges ----------------------------------------------------------- */
.badge {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: var(--s-1) var(--s-3);
  font-size: var(--fs-xs); font-weight: 600;
  border: 1px solid var(--surface-line); border-radius: var(--radius-pill);
  color: var(--text-mid); background: var(--surface-1);
}
.badge--demo { border-color: var(--y-yellow); color: var(--accent-ink); }

/* --- FAQ (every service page carries one) ----------------------------- */
.faq { max-width: 68ch; }
.faq__item { border-bottom: 1px solid var(--surface-line); }
/* Questions were set at --fs-h3 (up to 28px), so nearly every one wrapped onto
   a second line and each row ran ~90px tall — a list of eight became a page of
   its own. A question is a label, not a headline: one line each, and the
   answer underneath is where the reading actually happens. */
.faq__q {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
  padding: var(--s-4) 0; cursor: pointer;
  font-family: var(--font-display); font-size: var(--fs-body-lg);
  line-height: var(--lh-snug);
  color: var(--text-hi); list-style: none;
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q::after {
  content: "+"; font-family: var(--font-mono); font-size: 1.15rem;
  color: var(--accent-ink); flex: 0 0 auto;
  transition: transform var(--dur) var(--ease-out);
}
.faq__item[open] .faq__q::after { transform: rotate(45deg); }
.faq__a { padding-bottom: var(--s-4); }
.faq__a p { font-size: var(--fs-sm); line-height: var(--lh-body); }
.faq__a p { color: var(--text-mid); margin: 0 0 var(--s-3); }
.faq__a p:last-child { margin-bottom: 0; }

/* --- Closing band ----------------------------------------------------- */
.closing {
  position: relative; overflow: hidden;
  padding-block: clamp(4rem, 2rem + 9vw, 8rem);
  border-top: 1px solid var(--surface-line);
  text-align: center;
}
.closing__glow {
  position: absolute; bottom: -40%; left: 50%;
  width: min(120vw, 900px); aspect-ratio: 1; transform: translateX(-50%);
  background: radial-gradient(circle,
              color-mix(in srgb, var(--y-red) 20%, transparent) 0%, transparent 60%);
  pointer-events: none; will-change: transform;
}
.closing__inner { position: relative; }
.closing h2 { font-size: var(--fs-hero); max-width: 16ch; margin-inline: auto; }
.closing p { max-width: 52ch; margin-inline: auto; margin-bottom: var(--s-8);
             font-size: var(--fs-body-lg); }
.closing .hero__cta { justify-content: center; }

/* --- Breadcrumbs ------------------------------------------------------ */
.crumbs { display: flex; flex-wrap: wrap; gap: var(--s-2); font-size: var(--fs-sm); color: var(--text-lo); }
.crumbs a { text-decoration: none; }
.crumbs li + li::before { content: "/"; margin-inline-end: var(--s-2); color: var(--surface-line); }
.crumbs li { display: flex; }

/* --- Footer ----------------------------------------------------------- */
.footer {
  border-top: 1px solid var(--surface-line);
  padding-block: var(--s-16) var(--s-8);
  background: var(--surface-1);
}
.footer__grid { display: grid; gap: var(--s-12); grid-template-columns: 1fr; }
@media (min-width: 48rem)  { .footer__grid { grid-template-columns: repeat(2, 1fr); } }
/* Five columns since Company was added. The brand block keeps the widest
   share and contact keeps enough for an address that must not wrap mid-line. */
@media (min-width: 62rem)  { .footer__grid { grid-template-columns: 1.7fr 1fr 1fr 1fr 1.5fr; } }

.footer__pitch { color: var(--text-lo); font-size: var(--fs-sm); margin-top: var(--s-4); }
.footer__h { font-size: var(--fs-sm); font-family: var(--font-body); font-weight: 700;
             color: var(--text-hi); text-transform: uppercase;
             letter-spacing: var(--tracking-eyebrow); margin-bottom: var(--s-4); }
.footer__col ul li { margin-bottom: var(--s-2); }
.footer__col a { font-size: var(--fs-sm); color: var(--text-lo); text-decoration: none; }
.footer__col a:hover { color: var(--accent-ink); }

.footer__social { display: flex; flex-wrap: wrap; gap: var(--s-4); margin-top: var(--s-6); }
.footer__social a { font-size: var(--fs-sm); color: var(--text-mid); text-decoration: none; }

.footer__address { font-style: normal; font-size: var(--fs-sm); color: var(--text-lo); line-height: 1.7; }
.footer__contactlinks { margin-top: var(--s-3); }
.footer__contactlinks a { font-size: var(--fs-sm); color: var(--text-mid); text-decoration: none; }

.footer__news { margin-top: var(--s-6); }
.footer__newslabel { display: block; font-size: var(--fs-sm); color: var(--text-mid); margin-bottom: var(--s-2); }
.footer__newsrow { display: flex; gap: var(--s-2); }
.footer__newsnote { font-size: var(--fs-xs); color: var(--text-lo); margin-top: var(--s-2); }

.footer__bar {
  display: flex; flex-wrap: wrap; gap: var(--s-4);
  align-items: center; justify-content: space-between;
  margin-top: var(--s-12); padding-top: var(--s-6);
  border-top: 1px solid var(--surface-line);
}
.footer__copy { font-size: var(--fs-sm); color: var(--text-lo); margin: 0; }
.footer__legal { display: flex; flex-wrap: wrap; gap: var(--s-4); }
.footer__legal a { font-size: var(--fs-sm); color: var(--text-lo); text-decoration: none; }
/* Orphaned 2026-09-22: the footer's non-affiliation paragraph was removed at
   the owner's request and nothing carries this class now. Kept rather than
   deleted because the statement still exists on /disclaimer/ and /terms/, and
   if it is ever restored to the footer it should come back looking the same. */
.footer__disclaim {
  font-size: var(--fs-xs); color: var(--text-lo);
  margin-top: var(--s-6); max-width: 80ch; opacity: 0.8;
}

/* --- Theme toggle -------------------------------------------------------
   Both icons are in the DOM; CSS picks one from the theme class on <html>.
   That means the control is already correct at first paint — no JS needed to
   render it, only to change it. */
.theme-toggle {
  display: inline-grid; place-content: center;
  width: 40px; height: 40px; flex: 0 0 auto;
  background: transparent; color: var(--text-mid);
  border: 1px solid var(--surface-line); border-radius: var(--radius-pill);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-spring);
}
.theme-toggle:hover { color: var(--y-yellow); border-color: var(--y-yellow); }
.theme-toggle:active { transform: scale(0.94); }
.theme-toggle svg { grid-area: 1 / 1; transition: opacity var(--dur) var(--ease-out),
                                                  transform var(--dur) var(--ease-out); }

/* Dark theme -> offer the sun (switch to light). Light -> offer the moon. */
.theme-toggle__moon { opacity: 0; transform: rotate(-45deg) scale(0.6); }
.theme-toggle__sun  { opacity: 1; transform: none; }
.theme-light .theme-toggle__sun  { opacity: 0; transform: rotate(45deg) scale(0.6); }
.theme-light .theme-toggle__moon { opacity: 1; transform: none; }

/* The whole page cross-fades rather than snapping. Deliberately excludes
   transform so it never fights a GSAP tween mid-flight. */
.theme-anim, .theme-anim * {
  transition: background-color 240ms var(--ease-out),
              border-color 240ms var(--ease-out),
              color 240ms var(--ease-out) !important;
}

/* --- Hero artwork -------------------------------------------------------
   A framed panel beside the type, not a banner behind it. */
.hero__grid {
  display: grid; gap: var(--s-8); grid-template-columns: 1fr; align-items: center;
}
@media (min-width: 62rem) {
  /* 7/5 again. A 50/50 split makes the photo compete with the headline. */
  .hero__grid { grid-template-columns: 7fr 5fr; gap: var(--s-12); }
}
.hero__media {
  position: relative; border-radius: var(--radius-lg); overflow: hidden;
  border: 1px solid var(--surface-line); box-shadow: var(--shadow-card);
  aspect-ratio: 4 / 3;
}
.hero__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* A yellow wash ties stock photography to the brand instead of leaving it
   looking bought-in. Subtle: enough to unify, not enough to tint faces. */
.hero__media::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(140deg,
              color-mix(in srgb, var(--y-yellow) 16%, transparent) 0%,
              transparent 45%,
              color-mix(in srgb, var(--y-red) 10%, transparent) 100%);
  mix-blend-mode: overlay;
}
@media (max-width: 61.99rem) { .hero__media { aspect-ratio: 16 / 9; } }

/* --------------------------------------------------------------------------
   Footer map.
   Lazy-loaded: the footer is below the fold on every page, so the embed is
   only fetched on views where someone scrolls to the bottom.
   -------------------------------------------------------------------------- */
.footer__map {
  position: relative;
  margin-top: var(--s-6);
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--surface-line);
  background: var(--surface-2);
  aspect-ratio: 16 / 10;
  max-width: 22rem;
}
.footer__map iframe { width: 100%; height: 100%; border: 0; display: block; }

/* ── THE BRAND LABEL OVER A MAP PIN ────────────────────────────────────────
   Shared by every embedded map on the site (footer, /about/#reach, /contact/),
   which is why it lives in site.css rather than in one page's stylesheet.

   Google's basic embed gives no way to label its marker — that needs the Embed
   API and a key, which is not worth introducing for one word. So the label is
   ours, painted over the iframe and anchored to the CENTRE of the box, which
   is exactly where Google drops its pin because every map here is centred on
   ORG_GEO.

   That equivalence is load-bearing: hand any of these embeds a text query
   again and Google re-centres on whatever it resolved, leaving this label
   pointing at the wrong roof.

   The 42px lift clears Google's marker, whose tip sits ON the centre point
   with a balloon rising ~30px above it. The marker is a fixed pixel size at
   every map size, so this one offset is correct on the 22rem footer map and
   the 34rem one on /about/ alike.

   The parent needs `position: relative` — .footer__map, .abMap and
   .contact__map all set it. */
.mapTag {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, calc(-100% - 42px));
  /* Never block dragging or zooming the map underneath. */
  pointer-events: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: .3rem .6rem .3rem .4rem;
  border-radius: 999px;
  background: var(--y-yellow);
  color: var(--y-black);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: .01em;
  line-height: 1.2;
  white-space: nowrap;
  /* A light chip on a light map needs a rim, not just a drop shadow. */
  box-shadow: 0 0 0 1.5px rgb(0 0 0 / .18), 0 6px 16px -4px rgb(0 0 0 / .45);
}

.mapTag img { display: block; border-radius: 4px; }

/* The tail that ties the chip to the pin underneath it. */
.mapTag::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 100%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: var(--y-yellow);
}
.footer__maplink { margin: var(--s-3) 0 0; font-size: var(--fs-sm); }

/* --------------------------------------------------------------------------
   Signed-in user menu.

   Replaces "Log in / Join free" once a session exists — the bar was offering
   both to people who were already signed in, on the account page itself, which
   is the clearest possible way to tell somebody their login did not stick.
   -------------------------------------------------------------------------- */
.usermenu { position: relative; }

.usermenu__btn {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: var(--s-1) var(--s-3) var(--s-1) var(--s-1);
  border-radius: var(--radius-pill);
  border: 1px solid var(--surface-line);
  background: var(--surface-1);
  color: var(--text-hi);
  cursor: pointer;
  transition: border-color var(--dur) var(--ease-out), background var(--dur) var(--ease-out);
}
.usermenu__btn:hover { border-color: rgb(240 198 74 / 0.5); background: var(--surface-2); }

.usermenu__pic {
  width: 2rem; height: 2rem; border-radius: 50%;
  object-fit: cover; display: grid; place-items: center; flex: none;
}
.usermenu__pic--ini {
  background: var(--y-yellow); color: var(--y-black);
  font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0.02em;
}
.usermenu__name { font-size: var(--fs-sm); font-weight: 500; }
.usermenu__caret { color: var(--text-lo); transition: transform var(--dur) var(--ease-out); }
.usermenu__btn[aria-expanded="true"] .usermenu__caret { transform: rotate(180deg); }

.usermenu__panel {
  position: absolute; right: 0; top: calc(100% + var(--s-2));
  z-index: var(--z-dropdown);
  min-width: 15rem;
  padding: var(--s-3);
  border-radius: var(--radius);
  border: 1px solid var(--surface-line);
  background: var(--surface-1);
  box-shadow: var(--shadow-card);
  display: grid; gap: 2px;
}
/* On the light theme --surface-1 is pure white and the page is #FFFDF7, so the
   panel was white-on-white behind a hairline border — open, correctly sized,
   and completely invisible. A dropdown has to read as a layer ABOVE the page,
   which on a light ground means a real shadow, not a 1px line. */
.theme-light .usermenu__panel {
  border-color: rgb(28 28 28 / 0.10);
  box-shadow: 0 1px 2px rgb(28 28 28 / 0.06),
              0 12px 28px -8px rgb(28 28 28 / 0.18),
              0 32px 64px -24px rgb(28 28 28 / 0.22);
}
/* [hidden] loses to `display: grid` on specificity, the same trap that once
   left both nav menus visible at the same time. */
.usermenu__panel[hidden] { display: none; }

.usermenu__who {
  display: grid; gap: 2px; margin: 0;
  padding: var(--s-2) var(--s-3) var(--s-3);
  border-bottom: 1px solid var(--surface-line);
  margin-bottom: var(--s-2);
  max-width: none;
}
.usermenu__who strong { color: var(--text-hi); font-size: var(--fs-sm); }
.usermenu__who span { color: var(--text-lo); font-size: var(--fs-xs); overflow-wrap: anywhere; }

.usermenu__panel a,
.usermenu__out {
  display: block; width: 100%; text-align: left;
  padding: var(--s-2) var(--s-3);
  border: 0; background: none; cursor: pointer;
  border-radius: var(--radius-sm);
  color: var(--text-mid); font-size: var(--fs-sm); text-decoration: none;
  font: inherit; font-size: var(--fs-sm);
}
.usermenu__panel a:hover,
.usermenu__out:hover { background: var(--surface-2); color: var(--text-hi); }
.usermenu__out { color: var(--y-red); margin-top: var(--s-2); border-top: 1px solid var(--surface-line); border-radius: 0 0 var(--radius-sm) var(--radius-sm); }

@media (max-width: 60rem) { .usermenu { display: none; } }

/* --------------------------------------------------------------------------
   Mobile menu profile card.
   The desktop bar gets a dropdown; on a phone the menu IS the dropdown, so the
   identity belongs at the top of the sheet rather than as two buttons at the
   bottom of it.
   -------------------------------------------------------------------------- */
.mprofile {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-4);
  margin-bottom: var(--s-4);
  border-radius: var(--radius);
  border: 1px solid var(--surface-line);
  background: linear-gradient(140deg, rgb(240 198 74 / 0.10), var(--surface-1));
  text-decoration: none;
  transition: border-color var(--dur) var(--ease-out);
}
.mprofile:hover { border-color: rgb(240 198 74 / 0.5); }

.mprofile__pic {
  width: 3.25rem; height: 3.25rem; border-radius: 50%;
  object-fit: cover; display: grid; place-items: center; flex: none;
}
.mprofile__pic--ini {
  background: var(--y-yellow); color: var(--y-black);
  font-weight: 600; font-size: var(--fs-body);
}
.mprofile__text { display: grid; gap: 2px; min-width: 0; }
.mprofile__text strong { color: var(--text-hi); font-size: var(--fs-body-lg); }
.mprofile__text span {
  color: var(--text-lo); font-size: var(--fs-sm);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mprofile__go { color: var(--y-yellow); flex: none; }
.mprofile__links { margin-bottom: var(--s-4); }

/* ══════════════════════════════════════════════════════════════════════════
   GLOBAL SEARCH — command palette
   Lives in site.css because it is on every page; a separate stylesheet would
   be a second request on every page for ~90 lines.
   ══════════════════════════════════════════════════════════════════════════ */
.ycs {
  position: fixed; inset: 0; z-index: 200;
  display: grid; align-items: start; justify-items: center;
  padding: clamp(var(--s-8), 12vh, var(--s-32)) var(--gutter) var(--s-8);
  background: rgb(8 8 10 / .72);
  backdrop-filter: blur(6px);
}
.ycs[hidden] { display: none; }

.ycs__panel {
  width: min(40rem, 100%);
  border-radius: var(--radius-lg);
  border: 1px solid var(--surface-line);
  background: var(--surface-1);
  box-shadow: 0 40px 90px -30px rgb(0 0 0 / .9);
  overflow: hidden;
  display: grid; grid-template-rows: auto minmax(0, 1fr) auto;
  max-height: min(32rem, 70vh);
}

.ycs__bar {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--surface-line);
}
.ycs__bar svg { width: 1.1rem; height: 1.1rem; color: var(--text-lo); flex: none; }
.ycs__in {
  flex: 1; min-width: 0;
  border: 0; background: none; padding: 0;
  font: inherit; font-size: var(--fs-body-lg); color: var(--text-hi);
}
.ycs__in:focus { outline: none; }
.ycs__in::placeholder { color: var(--text-lo); }
.ycs__esc {
  flex: none; border: 0; padding: .2rem .5rem; cursor: pointer;
  border-radius: 5px; background: var(--surface-2);
  font-family: var(--font-mono); font-size: .62rem; color: var(--text-lo);
}

.ycs__res { overflow-y: auto; padding: var(--s-2); }
.ycsGroup {
  margin: var(--s-3) var(--s-3) var(--s-1);
  font-family: var(--font-mono); font-size: .6rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--text-lo);
}
.ycsHit {
  display: grid; gap: .1rem;
  padding: .6rem var(--s-3); border-radius: var(--radius);
  text-decoration: none;
  /* No transition on the highlight. The selection follows the arrow keys and
     a fade makes held-down navigation look like it is lagging behind. */
}
.ycsHit.is-on { background: var(--surface-2); }
.ycsHit__t { font-size: var(--fs-sm); font-weight: 600; color: var(--text-hi); }
.ycsHit__m {
  font-size: var(--fs-xs); color: var(--text-lo);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ycsHit.is-on .ycsHit__m { color: var(--text-mid); }

.ycs__foot {
  padding: var(--s-3) var(--s-5);
  border-top: 1px solid var(--surface-line);
  font-size: var(--fs-xs); color: var(--text-lo);
}

/* The nav trigger. Hidden on phones — a 44px target for a feature whose whole
   point is a keyboard shortcut is not worth the width on a 390px screen. */
.navSearch {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: .4rem .7rem; border-radius: var(--radius-pill);
  border: 1px solid var(--surface-line); background: var(--surface-1);
  cursor: pointer; font: inherit; font-size: var(--fs-xs); color: var(--text-lo);
  transition: border-color var(--dur) var(--ease-out), color var(--dur) var(--ease-out);
}
.navSearch:hover { border-color: var(--y-yellow); color: var(--text-hi); }
.navSearch svg { width: .9rem; height: .9rem; }
.navSearch kbd {
  padding: .05rem .3rem; border-radius: 4px;
  background: var(--surface-2); border: 1px solid var(--surface-line);
  font-family: var(--font-mono); font-size: .58rem;
}
/* The pill COLLAPSES to its icon when the bar tightens — it is not swapped
   for the other search control. `.nav__search` is a sibling that sits after
   .nav__actions in the DOM, so showing it at desktop would put the magnifier
   on the far side of "Join free". Dropping the word and the ⌘K hint saves the
   same ~62px and keeps search where it has always been, next to the theme
   toggle. (The hint is no loss here either: a viewport this narrow is a
   laptop being used in a half-screen window as often as not.) */
@media (max-width: 87.99rem) {
  .navSearch { gap: 0; width: 2.2rem; height: 2.2rem; padding: 0; justify-content: center; border-radius: 50%; }
  .navSearch span, .navSearch kbd { display: none; }
}
/* Below the desktop tiers the bar has no actions at all; the round
   .nav__search beside the burger is the phone control. */
@media (max-width: 63.99rem) { .navSearch { display: none; } }

/* ── search inside the mobile sheet ────────────────────────────────────────
   .navSearch is hidden below 62rem because a ⌘K hint means nothing on a
   phone. The SEARCH still does, so the sheet carries its own full-width
   trigger — without it the feature was unreachable on the device most of this
   audience uses. */
.msearch {
  display: flex; align-items: center; gap: var(--s-3); width: 100%;
  margin-bottom: var(--s-6); padding: var(--s-4);
  border-radius: var(--radius); border: 1px solid var(--surface-line);
  background: var(--surface-1); cursor: pointer;
  font: inherit; font-size: var(--fs-body); color: var(--text-lo);
  text-align: left;
}
.msearch:hover, .msearch:focus-visible { border-color: var(--y-yellow); color: var(--text-hi); }
.msearch svg { flex: none; width: 1.1rem; height: 1.1rem; }

/* ── search in the mobile bar ──────────────────────────────────────────────
   Sits beside the burger, visible without opening anything. Hidden at desktop,
   where .navSearch already shows the labelled control with its ⌘K hint. */
.nav__search {
  display: none;
  align-items: center; justify-content: center;
  width: 2.6rem; height: 2.6rem; flex: none;
  border-radius: 50%; border: 1px solid var(--surface-line);
  background: var(--surface-1); color: var(--text-mid); cursor: pointer;
  transition: color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out);
}
.nav__search svg { width: 1.15rem; height: 1.15rem; }
.nav__search:hover, .nav__search:focus-visible { color: var(--text-hi); border-color: var(--y-yellow); }
@media (max-width: 63.99rem) { .nav__search { display: inline-flex; } }

/* ══════════════════════════════════════════════════════════════════════════
   AUDIENCE BANDS — the line between the two halves of the company
   ══════════════════════════════════════════════════════════════════════════ */
.audband {
  position: relative;
  padding: clamp(var(--s-6), 3.5vh, var(--s-10)) var(--gutter) 0;
}

/* The dead space ABOVE the rule was never the band's — it is the preceding
   section's own bottom padding, which is sized for a gap between two full
   sections, not for a divider that belongs to the one below it. Scoped with
   :has() so only the section immediately before a band is tightened, and every
   other section on the site keeps its normal rhythm. */
section:has(+ .audband) { padding-bottom: clamp(var(--s-8), 4vh, var(--s-12)); }

/* Likewise below: the band and the section under it are ONE unit, so the
   section does not need its full opening padding as well. */
.audband + section { padding-top: var(--s-6); }
.audband__in { width: min(var(--container), 100%); margin-inline: auto; }

/* A rule above the label, so the band reads as a divider and not as another
   section heading competing with the one below it. */
.audband__in::before {
  content: ''; display: block; width: 100%; height: 1px; margin-bottom: var(--s-5);
  background: linear-gradient(90deg, var(--h-col), transparent 70%);
}
.audband--stu { --h-col: rgb(240 198 74 / .6); }
.audband--biz { --h-col: rgb(232 84 74 / .6); }

.audband__k {
  display: inline-block; margin: 0 0 var(--s-4);
  padding: .3rem .9rem; border-radius: var(--radius-pill);
  border: 1px solid var(--h-col);
  background: color-mix(in srgb, var(--h-col) 12%, transparent);
  font-family: var(--font-mono); font-size: .68rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--text-hi);
}
.audband__h {
  margin: 0 0 var(--s-3); max-width: 20ch;
  font-family: var(--font-display); font-size: clamp(2rem, 5.5vw, 3.6rem);
  line-height: 1.02; letter-spacing: -.035em; color: var(--text-hi);
}
.audband__p {
  margin: 0; max-width: 54ch;
  font-size: var(--fs-body-lg); line-height: var(--lh-body); color: var(--text-lo);
}

@media (max-width: 46rem) {
  .audband { padding-top: var(--s-6); }
  .audband__h { font-size: clamp(1.7rem, 8vw, 2.4rem); }
}

/* A label-only band. Without this it keeps the full band's bottom padding and
   leaves a screen of empty space between the chip and the section under it. */
.audband--label { padding-bottom: 0; }
.audband--label .audband__k { margin-bottom: 0; }

/* ══════════════════════════════════════════════════════════════════════════
   FEEDBACK & IDEAS — site-wide dialog (layout_end + feedback.js)
   ══════════════════════════════════════════════════════════════════════════ */
.ycfb { position: fixed; inset: 0; z-index: 900; display: grid; place-items: center; padding: var(--s-4); }
.ycfb[hidden] { display: none; }
.ycfb__veil { position: absolute; inset: 0; border: 0; background: rgb(0 0 0 / .6); backdrop-filter: blur(4px); cursor: default; }
.ycfb__box {
  position: relative; width: min(32rem, 100%); max-height: calc(100dvh - 2rem); overflow-y: auto;
  padding: var(--s-6); border-radius: var(--radius-lg); border: 1px solid var(--border, rgb(255 255 255 / .1));
  background: var(--surface-2); color: var(--text-hi); box-shadow: 0 30px 80px -30px rgb(0 0 0 / .9);
}
.ycfb__top { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); margin-bottom: var(--s-2); }
.ycfb__top h2 { margin: 0; font-size: var(--fs-h3); }
.ycfb__x { border: 0; background: none; color: var(--text-mid); font-size: 1.6rem; line-height: 1; cursor: pointer; padding: .2rem .4rem; }
.ycfb__x:hover { color: var(--text-hi); }
.ycfb__lead { color: var(--text-mid); font-size: var(--fs-sm); margin-bottom: var(--s-4); }
.ycfb__kinds { display: flex; flex-wrap: wrap; gap: .4rem; margin-bottom: var(--s-4); }
.ycfb__kinds label { cursor: pointer; }
.ycfb__kinds input { position: absolute; opacity: 0; pointer-events: none; }
.ycfb__kinds span {
  display: inline-block; padding: .45rem .85rem; border-radius: var(--radius-pill); font-size: var(--fs-sm);
  border: 1px solid var(--border, rgb(255 255 255 / .12)); color: var(--text-mid);
  transition: border-color var(--dur) var(--ease-out), background-color var(--dur) var(--ease-out), color var(--dur) var(--ease-out);
}
.ycfb__kinds input:checked + span { border-color: var(--y-yellow); background: rgb(240 198 74 / .1); color: var(--text-hi); }
.ycfb__kinds input:focus-visible + span { outline: 2px solid var(--y-yellow); outline-offset: 2px; }
.ycfb__field { display: grid; gap: .35rem; margin-bottom: var(--s-4); font-size: var(--fs-sm); color: var(--text-mid); }
.ycfb__field i { font-style: normal; color: var(--text-lo); }
.ycfb__field textarea, .ycfb__field input {
  width: 100%; padding: .7rem .85rem; border-radius: var(--radius); font: inherit; font-size: 1rem;
  border: 1px solid var(--border, rgb(255 255 255 / .12)); background: var(--surface-0, rgb(0 0 0 / .25)); color: var(--text-hi);
  resize: vertical;
}
.ycfb__field textarea:focus, .ycfb__field input:focus { outline: none; border-color: var(--y-yellow); }
.ycfb__hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.ycfb__err { color: var(--y-red); font-size: var(--fs-sm); margin: 0 0 var(--s-3); max-width: none; }
.ycfb__foot { display: flex; justify-content: flex-end; gap: var(--s-2); }
.ycfb__box.is-done > :not(.ycfb__done):not(.ycfb__top) { display: none; }
.ycfb__done { text-align: center; padding: var(--s-4) 0 var(--s-2); }
.ycfb__done p { max-width: none; color: var(--text-mid); font-size: var(--fs-sm); }
.ycfb__done h3 { margin: 0 0 var(--s-2); font-size: var(--fs-body-lg); }

/* ── Form rows never push their button off a phone screen ──────────────────
   A text input has an intrinsic width of ~20 characters and, as a flex item,
   will not shrink below it unless told to — so on a 320px phone the Search
   button beside it was pushed 18–25px off-screen (/community/rooms/,
   /community/discover/). min-width: 0 lets the field give way instead. */
form input:not([type="checkbox"]):not([type="radio"]),
form select, form textarea { min-width: 0; max-width: 100%; }
.cmpSearch input, .rmSearch input { flex: 1 1 auto; width: auto; }
.cmpSearch .cmxBtn, .rmSearch .cmxBtn { flex: none; }

/* ── "Add Ycotes to your home screen" (install.js) ─────────────────────── */
.ycInst {
  position: fixed; z-index: 990; right: max(1rem, env(safe-area-inset-right)); bottom: max(1rem, env(safe-area-inset-bottom));
  width: min(23rem, calc(100vw - 2rem)); padding: 1rem; display: grid; gap: .85rem;
  border-radius: 1.1rem; border: 1px solid rgb(240 198 74 / .35);
  background: radial-gradient(120% 90% at 100% 0%, rgb(240 198 74 / .14), transparent 60%), #16161a;
  color: #f4f4f5; box-shadow: 0 30px 70px -25px rgb(0 0 0 / .9);
  animation: ycInstIn .45s cubic-bezier(.2,.9,.3,1.15) both;
}
.ycInst.is-leaving { animation: ycInstOut .25s ease both; }
.ycInst__head { display: flex; gap: .8rem; align-items: flex-start; }
.ycInst__icon { flex: none; width: 3.1rem; height: 3.1rem; border-radius: .85rem; box-shadow: 0 6px 18px -6px rgb(240 198 74 / .6);
  animation: ycInstBob 3s ease-in-out 1s infinite; }
.ycInst__t { display: grid; gap: .2rem; min-width: 0; flex: 1; }
.ycInst__t b { font-size: 1rem; }
.ycInst__t span { font-size: .8rem; line-height: 1.45; color: #b6b6bd; }
.ycInst__x { flex: none; width: 2rem; height: 2rem; border-radius: 50%; border: 1px solid rgb(255 255 255 / .12);
  background: transparent; color: #b6b6bd; font-size: 1.2rem; line-height: 1; cursor: pointer; }
.ycInst__x:hover { color: #fff; }
.ycInst__row { display: flex; gap: .6rem; }
.ycInst__later, .ycInst__go { flex: 1; min-height: 2.75rem; border-radius: 999px; font: inherit; font-size: .9rem; font-weight: 600; cursor: pointer; }
.ycInst__later { border: 1px solid rgb(255 255 255 / .16); background: transparent; color: #e4e4e7; }
.ycInst__later--full { flex: none; width: 100%; }
.ycInst__go { display: inline-flex; align-items: center; justify-content: center; gap: .45rem; border: 0;
  background: linear-gradient(135deg, #f7d774, #f0c64a); color: #111; box-shadow: 0 10px 24px -12px rgb(240 198 74 / .9); }
.ycInst__go:hover { filter: brightness(1.05); }
.ycInst__steps { list-style: none; margin: 0; padding: 0; display: grid; gap: .55rem; }
.ycInst__steps li { display: flex; align-items: center; flex-wrap: wrap; gap: .45rem; font-size: .85rem; color: #d4d4d8; }
.ycInst__n { display: inline-grid; place-items: center; width: 1.4rem; height: 1.4rem; border-radius: 50%;
  background: rgb(240 198 74 / .18); color: #f0c64a; font-size: .72rem; font-weight: 700; }
.ycInst__chip { display: inline-flex; align-items: center; gap: .3rem; padding: .15rem .55rem; border-radius: 999px;
  background: rgb(255 255 255 / .08); color: #fff; font-weight: 600; }
.ycInst__arrow { display: none; }
.ycInst__toast { position: fixed; z-index: 995; left: 50%; bottom: max(1.25rem, env(safe-area-inset-bottom)); translate: -50% 1rem;
  max-width: calc(100vw - 2rem); padding: .65rem 1rem; border-radius: 999px; background: #1f1f24; color: #f4f4f5;
  border: 1px solid rgb(255 255 255 / .12); font-size: .85rem; opacity: 0; transition: opacity .25s, translate .25s; pointer-events: none; }
.ycInst__toast.is-on { opacity: 1; translate: -50% 0; }
@keyframes ycInstIn { from { opacity: 0; transform: translateY(24px) scale(.96); } to { opacity: 1; transform: none; } }
@keyframes ycInstOut { to { opacity: 0; transform: translateY(20px); } }
@keyframes ycInstBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
@media (max-width: 46rem) {
  .ycInst { left: .6rem; right: .6rem; bottom: calc(.6rem + env(safe-area-inset-bottom)); width: auto; }
  /* iPhone: Safari's Share button is in the bottom bar — point at it. */
  .ycInst__arrow { display: block; justify-self: center; margin: -.4rem 0 -.3rem; color: #f0c64a; font-size: 1.3rem;
    animation: ycInstBob 1.4s ease-in-out infinite; }
}
.theme-light .ycInst { background: radial-gradient(120% 90% at 100% 0%, rgb(240 198 74 / .18), transparent 60%), #fff; color: #111; border-color: rgb(184 134 11 / .35); }
.theme-light .ycInst__t span, .theme-light .ycInst__steps li { color: #52525b; }
.theme-light .ycInst__later { color: #27272a; border-color: rgb(0 0 0 / .15); }
.theme-light .ycInst__chip { background: rgb(0 0 0 / .06); color: #111; }
@media (prefers-reduced-motion: reduce) { .ycInst, .ycInst__icon, .ycInst__arrow { animation: none; } }

/* ── "Turn on notifications" (push.js) ─────────────────────────────────────
   Same family as the install card, with a ringing bell so it reads as
   "notifications" at a glance. Sits above the community tab bar on phones. */
.ycPush {
  position: fixed; z-index: 991; right: max(1rem, env(safe-area-inset-right)); bottom: max(1rem, env(safe-area-inset-bottom));
  width: min(23rem, calc(100vw - 2rem)); padding: 1rem; display: grid; gap: .85rem;
  border-radius: 1.1rem; border: 1px solid rgb(240 198 74 / .35);
  background: radial-gradient(120% 90% at 0% 0%, rgb(240 198 74 / .16), transparent 60%), #16161a;
  color: #f4f4f5; box-shadow: 0 30px 70px -25px rgb(0 0 0 / .9);
  animation: ycInstIn .45s cubic-bezier(.2,.9,.3,1.15) both;
}
.ycPush.is-leaving { animation: ycInstOut .25s ease both; }
.ycPush.is-done { border-color: rgb(62 158 95 / .6); }
.ycPush__head { display: flex; gap: .8rem; align-items: flex-start; }
.ycPush__bell {
  position: relative; flex: none; width: 3rem; height: 3rem; display: grid; place-items: center;
  border-radius: .9rem; background: linear-gradient(135deg, #f7d774, #f0c64a); color: #111;
  box-shadow: 0 8px 20px -8px rgb(240 198 74 / .7);
}
.ycPush__bell svg { width: 1.45rem; height: 1.45rem; fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; transform-origin: 50% 15%;
  animation: ycPushRing 2.6s ease-in-out .6s infinite; }
.ycPush__bell i { position: absolute; top: -.25rem; right: -.25rem; width: .8rem; height: .8rem; border-radius: 50%;
  background: #e8544a; box-shadow: 0 0 0 2px #16161a; animation: ycPushDot 2.6s ease-in-out .6s infinite; }
.ycPush.is-done .ycPush__bell { background: linear-gradient(135deg, #5ad08a, #3e9e5f); }
.ycPush.is-done .ycPush__bell svg, .ycPush.is-done .ycPush__bell i { animation: none; }
.ycPush.is-done .ycPush__bell i { display: none; }
.ycPush__t { display: grid; gap: .2rem; min-width: 0; flex: 1; }
.ycPush__t b { font-size: 1rem; }
.ycPush__t span { font-size: .8rem; line-height: 1.45; color: #b6b6bd; }
.ycPush__x { flex: none; width: 2rem; height: 2rem; border-radius: 50%; border: 1px solid rgb(255 255 255 / .12);
  background: transparent; color: #b6b6bd; font-size: 1.2rem; line-height: 1; cursor: pointer; }
.ycPush__x:hover { color: #fff; }
.ycPush__row { display: flex; gap: .6rem; }
.ycPush__later, .ycPush__go { flex: 1; min-height: 2.75rem; border-radius: 999px; font: inherit; font-size: .9rem; font-weight: 600; cursor: pointer; }
.ycPush__later { border: 1px solid rgb(255 255 255 / .16); background: transparent; color: #e4e4e7; }
.ycPush__go { border: 0; background: linear-gradient(135deg, #f7d774, #f0c64a); color: #111;
  box-shadow: 0 10px 24px -12px rgb(240 198 74 / .9); }
.ycPush__go:hover { filter: brightness(1.05); }
.ycPush__go:disabled { opacity: .75; cursor: progress; }
@keyframes ycPushRing { 0%, 60%, 100% { transform: rotate(0); } 8% { transform: rotate(14deg); } 16% { transform: rotate(-12deg); }
  24% { transform: rotate(9deg); } 32% { transform: rotate(-6deg); } 40% { transform: rotate(3deg); } }
@keyframes ycPushDot { 0%, 60%, 100% { transform: scale(1); } 10% { transform: scale(1.35); } }
@media (max-width: 46rem) {
  .ycPush { left: .6rem; right: .6rem; width: auto; bottom: calc(.6rem + env(safe-area-inset-bottom)); }
  body:has(.cnBar:not(.is-convo)) .ycPush { bottom: calc(4.8rem + env(safe-area-inset-bottom)); }
}
@media (prefers-reduced-motion: reduce) { .ycPush__bell svg, .ycPush__bell i { animation: none; } }
.theme-light .ycPush { background: radial-gradient(120% 90% at 0% 0%, rgb(240 198 74 / .2), transparent 60%), #fff; color: #111; border-color: rgb(184 134 11 / .35); }
.theme-light .ycPush__t span { color: #52525b; }
.theme-light .ycPush__later { color: #111; border-color: rgb(0 0 0 / .15); }

/* ══════════════════════════════════════════════════════════════════════════
   iPHONE HOME-SCREEN APP — keep clear of the status bar
   Installed to the Home Screen, the app runs full-screen with
   `black-translucent` status bar + viewport-fit=cover: the page is drawn
   UNDER the clock and battery, so the header slid up behind them. Everything
   pinned to the top edge is pushed down by the status bar's height.
   env(safe-area-inset-top) is 0 in an ordinary browser tab, so this changes
   nothing anywhere except where it is needed. (`html` prefix = wins over the
   page stylesheets that load after this one.)
   ══════════════════════════════════════════════════════════════════════════ */
html .nav { padding-top: env(safe-area-inset-top); }
html .mobile-menu { padding-top: env(safe-area-inset-top); }
html .crlBar { top: calc(.8rem + env(safe-area-inset-top)); }
@media (max-width: 52rem) {
  html .stModal__box { padding-top: env(safe-area-inset-top); }          /* Settings, full-screen on a phone */
}
@media (max-width: 46rem) {
  html .ycs { padding-top: calc(var(--s-8) + env(safe-area-inset-top)); } /* search */
  html .cmxView__shell { padding-top: env(safe-area-inset-top); }         /* photo viewer */
  html .upView__box { padding-top: env(safe-area-inset-top); }            /* updates player */
  html .cmxAns__box { padding-top: env(safe-area-inset-top); }            /* answers panel */
  html .crlBar { top: calc(.4rem + env(safe-area-inset-top)); }           /* course player bar */
  html .crlExit { top: calc(.5rem + env(safe-area-inset-top)); }
}
