/* fengchao.life — Hive course ordering. Self-hosted styles, no external assets. */

/* Latin UI face. Google Sans is proprietary, so Inter stands in for it — the
   closest open face by measured overlap with it. One self-hosted 48 KB file
   (Google Fonts is unreachable in mainland China); the variable axis covers
   every weight used below. `unicode-range` keeps it to Latin so 中文 still
   comes from PingFang SC / YaHei. SIL OFL 1.1, see fonts/Inter-OFL.txt. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/inter-latin-var.woff2") format("woff2-variations");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* Palette matched to the EquipMe materials site: a cool light gray-blue
     ground (their actual page background, not the warm-white card behind the
     product image — sampled at #f2f4f8), near-black text, and a deep navy
     accent. */
  --bg: #f2f4f8;
  --card: #ffffff;
  --ink: #1c1c1c;
  /* Kept dark rather than a visibly "gray" tone — secondary text should read
     as black at a glance, just a shade lighter than headings, not muted-gray. */
  --muted: #333333;
  --line: #dde3ec;
  --accent: #1d4a83;
  --accent-dark: #123a63;
  --accent-soft: #e8eef5;
  --ok: #15803d;
  /* Not red (in Chinese-language UI, red text commonly reads as
     rejection/disagreement rather than neutral "error"), and not blue
     (the accent color, reserved for links/actions) — a deep amber keeps
     error/attention messages visually distinct from both. */
  --err: #b45309;
  --radius: 14px;
  --shadow: 0 1px 3px rgba(30, 41, 59, 0.07), 0 4px 14px rgba(30, 41, 59, 0.06);
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* Nearly every size in this file is in rem, so bumping the root size scales
   body copy, buttons, chips, and headings together — a straightforward fix
   for "everything reads a little small" without hand-tuning each rule. */
html { font-size: 17px; }
body {
  background: var(--bg);
  color: var(--ink);
  /* Latin fonts FIRST, CJK after — do not reorder. Fallback is per-character,
     so Latin comes from Inter and Chinese falls through to PingFang/YaHei.
     When the CJK fonts led this list, English rendered in a Chinese font's
     Latin glyphs instead. The system fonts stay as the first-paint fallback. */
  font-family: "Inter", "Segoe UI Variable Text", "Segoe UI", -apple-system,
               BlinkMacSystemFont, Roboto, "Helvetica Neue", Arial,
               "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
  line-height: 1.6;
  /* body fills at least the viewport and lays out header/main as a column,
     so main (.wrap) can flex to the exact remaining height below the header
     instead of guessing a vh value — see .panel-short below. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; }

/* Header */
/* Brand header. The 蜂巢 mark is gold; the rest of the UI stays blue, so the
   header carries the only warm accent on the page — a hairline under it picks
   up the logo's honey tone and ties the two palettes together. */
.site-header {
  position: sticky; top: 0; z-index: 20;
  background: rgba(255, 255, 255, 0.94);
  backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 1px 0 rgba(224, 168, 32, 0.28), 0 6px 18px -12px rgba(15, 32, 60, 0.28);
}
.header-inner {
  max-width: 1080px; margin: 0 auto; padding: 13px 20px;
  display: flex; align-items: center; gap: 13px;
  /* anchors the mobile nav panel, which drops out of the header */
  position: relative;
}
.logo-mark {
  width: 46px; height: 46px; flex: none;
  /* the mark is a flat honeycomb; a whisper of shadow lifts it off the header */
  filter: drop-shadow(0 1px 2px rgba(146, 100, 12, 0.22));
}
/* A hair of optical spacing: the wordmark sits slightly tighter to the mark
   than the tagline, so the lockup reads as one unit. */
.brand-lockup { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.brand-name {
  font-size: 1.32rem; font-weight: 700; line-height: 1.05;
  letter-spacing: 0.14em; text-indent: 0.14em;
  color: var(--ink);
}
.brand-line { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
/* The four values sit beside the wordmark, quieter than it but warmer than the
   tagline — they are a statement of principle, not a description. */
.brand-values {
  font-size: 0.76rem; letter-spacing: 0.08em; color: #a9781a;
  white-space: nowrap;
}
.brand-tag {
  font-size: 0.79rem; line-height: 1.25; color: var(--muted);
  letter-spacing: 0.02em;
  padding-left: 10px;
  border-left: 2px solid rgba(224, 168, 32, 0.55);
}

/* ---- site menus ---- */
.site-nav { display: flex; align-items: center; gap: 2px; }
.menu-group { position: relative; }
.menu-btn {
  display: inline-flex; align-items: center; gap: 5px;
  border: 1px solid transparent; background: none; color: var(--ink);
  font: inherit; font-size: 0.88rem; border-radius: 999px;
  padding: 7px 13px; cursor: pointer; white-space: nowrap;
}
.menu-btn:hover { background: #eef1f6; }
/* Top-level plain link (no dropdown) — same pill, no underline. */
a.menu-link { text-decoration: none; }
a.menu-link .ext-ic { font-size: 0.78rem; }
.menu-group.open > .menu-btn { background: #e8eef5; border-color: #c3d2e0; }
.menu-btn .caret { transition: transform 0.15s ease; flex: none; }
.menu-group.open .caret { transform: rotate(180deg); }
.menu-panel {
  display: none; position: absolute; right: 0; top: calc(100% + 6px);
  min-width: 250px; background: var(--card);
  border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 12px 32px -10px rgba(15, 32, 60, 0.3);
  padding: 6px; z-index: 40;
}
.menu-group.open .menu-panel { display: block; }
.menu-item {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 9px 12px; border-radius: 8px; font-size: 0.89rem;
  color: var(--ink); text-decoration: none;
}
a.menu-item:hover { background: #eef1f6; }
.menu-item .ext-ic { color: var(--muted); font-size: 0.8rem; }
/* Planned features read as unavailable rather than broken. */
.menu-item.is-soon { color: var(--muted); cursor: default; }
.soon-tag {
  font-size: 0.68rem; color: #a9781a; background: #fdf6e6;
  border: 1px solid #f0e0b8; border-radius: 999px; padding: 1px 7px;
  white-space: nowrap; flex: none;
}
.nav-toggle {
  display: none; align-items: center; gap: 6px; flex: none; white-space: nowrap;
  border: 1px solid var(--line); background: var(--card); color: var(--ink);
  border-radius: 999px; padding: 6px 13px; font: inherit; font-size: 0.85rem; cursor: pointer;
}

/* Below this width the three dropdowns cannot sit next to the brand, so the
   nav collapses behind a Menu button and opens as one stacked list. */
@media (max-width: 900px) {
  .nav-toggle { display: inline-flex; }
  .site-nav {
    display: none; position: absolute; left: 0; right: 0; top: 100%;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--card); border-top: 1px solid var(--line);
    box-shadow: 0 14px 30px -12px rgba(15, 32, 60, 0.3);
    padding: 8px; max-height: 70vh; overflow-y: auto;
  }
  .site-nav.expanded { display: flex; }
  .menu-btn { width: 100%; justify-content: space-between; border-radius: 10px; }
  .menu-panel {
    position: static; display: block; min-width: 0; border: none;
    box-shadow: none; padding: 0 0 6px 10px;
  }
  .menu-panel .menu-item { font-size: 0.86rem; }
}
@media (max-width: 560px) {
  .logo-mark { width: 38px; height: 38px; }
  .brand-name { font-size: 1.14rem; letter-spacing: 0.1em; text-indent: 0.1em; }
  .brand-tag { font-size: 0.7rem; padding-left: 8px; }
}
.header-spacer { flex: 1; }
.lang-btn {
  border: 1px solid var(--line); background: var(--card); color: var(--ink);
  border-radius: 999px; padding: 6px 16px; font-size: 0.85rem; cursor: pointer;
}
.lang-btn:hover { border-color: var(--accent); color: var(--accent-dark); }

/* Layout */
.wrap {
  max-width: 1080px; margin: 0 auto; padding: 24px 20px 96px;
  width: 100%; flex: 1; display: flex; flex-direction: column;
}
#app { display: flex; flex-direction: column; flex: 1; }
/* The three short "pick one" steps (level, track, philosophy) have only 2-3
   cards — left top-aligned, that reads as a mostly-empty page below a tall
   viewport. Because body/.wrap/#app are a flex column stretched to the full
   viewport height, this panel's flex:1 gives it exactly the space left below
   the stepper, and centering its own content turns the old bottom-heavy gap
   into balanced space above and below instead. Longer steps (requirements
   table, course grid, order form) don't get this class, so their natural
   content height still grows the page and scrolls normally. */
.panel-short {
  flex: 1; display: flex; flex-direction: column; justify-content: center;
  min-height: 320px;
}

/* Stepper */
.stepper { display: flex; gap: 4px; margin: 8px 0 28px; flex-wrap: wrap; }
.step-item {
  display: flex; align-items: center; gap: 8px; padding: 4px 10px 4px 4px; border-radius: 999px;
  color: var(--muted); font-size: 0.85rem;
  /* A completed step renders as a <button>; reset its default chrome so it
     still reads as a breadcrumb, not a form control. */
  border: none; background: none; font-family: inherit; line-height: inherit;
}
.step-item .dot {
  width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  background: #eef1f6; color: var(--muted); font-weight: 700; font-size: 0.8rem; flex: none;
}
.step-item.active { color: var(--accent-dark); font-weight: 600; }
.step-item.active .dot { background: var(--accent); color: #fff; }
.step-item.done .dot { background: var(--accent-soft); color: var(--accent-dark); }
/* Completed steps are clickable — jump back and revise an earlier choice. */
/* Any step the wizard can actually jump to is a real button: completed ones
   (.done) and ready-but-not-yet-visited ones (.ready). A step whose
   prerequisites are missing stays a plain div and explains itself on hover. */
button.step-item { cursor: pointer; }
button.step-item:hover { color: var(--accent-dark); background: var(--accent-soft); }
button.step-item:hover .dot { background: var(--accent-dark); color: #fff; }
button.step-item:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
div.step-item:not(.active) { cursor: not-allowed; }
.step-sep { align-self: center; color: var(--line); }

/* Panels */
.panel h2 { margin: 0 0 6px; font-size: 1.2rem; font-weight: 700; }
.panel .hint { color: var(--muted); margin: 0 0 28px; font-size: 0.98rem; }
/* Compact header for the course-list step: title and instructions share one
   line instead of a full heading line plus a separate hint paragraph, so the
   filter bar and course grid start higher and more cards show up front. */
.panel-head-line {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 14px;
  margin: 0 0 16px;
}
.panel-head-line h2 { margin: 0; font-size: 1.2rem; }
.panel-head-line .hint-inline { color: var(--muted); font-size: 0.82rem; }

/* Choice cards */
.choice-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 20px; }
.choice-card {
  background: var(--card); border: 2px solid var(--line); border-radius: var(--radius);
  padding: 28px 26px; cursor: pointer; box-shadow: var(--shadow);
  transition: border-color 0.15s, transform 0.15s; text-align: left;
  /* Top-aligned: with three stage cards whose descriptions run to different
     lengths, centred content made the icons and titles sit at three different
     heights and the row read as ragged. */
  display: flex; flex-direction: column; align-items: flex-start;
}
.choice-card:hover { border-color: var(--accent); transform: translateY(-2px); }
.choice-card.selected { border-color: var(--accent); background: var(--accent-soft); }
.choice-card h3 { margin: 0 0 8px; font-size: 0.98rem; }
.choice-card p { margin: 0; color: var(--muted); font-size: 0.92rem; }
.choice-card .hex { color: var(--accent); margin-bottom: 14px; }
.choice-card .hex svg { width: 32px; height: 32px; }

/* Requirements table */
.req-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden; }
.req-table { width: 100%; border-collapse: collapse; font-size: 0.95rem; }
.req-table th, .req-table td { padding: 10px 16px; border-bottom: 1px solid var(--line); text-align: left; }
.req-table th { background: #eef1f6; font-weight: 600; }
.req-table tr:last-child td { border-bottom: none; }
.req-table td.num { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }
.req-total td { background: var(--accent-soft); font-weight: 700; }

/* Requirements page: per-row course lists (see window.REQ_SUBJECTS in i18n.js).
   A row only becomes a disclosure when courses are actually available, so the
   table still reads as a plain reference table for rows with nothing to show. */
.req-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.req-toggle:hover { color: var(--accent); }
/* The expand control. It reads as a button, not as a stray character: a tinted
   disc in the accent color, big enough to be an obvious tap target on a phone,
   and the chevron rotates a quarter turn when the row opens. */
.req-caret {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; flex: none; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent);
  transition: transform 0.18s ease, background-color 0.18s ease;
}
.req-toggle:hover .req-caret { background: #d7e3f0; }
.req-row.open .req-caret { transform: rotate(90deg); }
.req-count { color: var(--muted); font-size: 0.8rem; font-weight: 400; }
.req-row.open .req-count { color: var(--accent); }
.req-courses td { background: #f7f9fc; padding-top: 8px; padding-bottom: 12px; }
.req-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.req-chip {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: 5px 10px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--card); color: var(--ink);
  font: inherit; font-size: 0.82rem; cursor: pointer; text-align: left;
}
.req-chip:hover { border-color: var(--accent); color: var(--accent); }
.req-chip-code { color: var(--muted); font-size: 0.74rem; letter-spacing: 0.03em; }
.req-chip-cr { color: var(--muted); font-size: 0.74rem; font-variant-numeric: tabular-nums; }
/* Already in the cart. Never red — that reads as rejection in Chinese UI. */
.req-chip.in-cart { border-color: var(--accent); background: var(--accent-soft); }
.req-chip-tick { color: var(--accent); font-size: 0.78rem; }
@media (max-width: 560px) { .req-chip { font-size: 0.78rem; } }
.policy { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 16px 20px; margin-top: 16px; box-shadow: var(--shadow); }
.policy h3 { margin: 0 0 8px; font-size: 1rem; color: var(--accent-dark); }
.policy pre { white-space: pre-wrap; font-family: inherit; margin: 0; font-size: 0.88rem; color: var(--muted); }

/* Filters */
.filter-bar {
  display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 18px;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px 14px; box-shadow: var(--shadow); position: sticky; top: 62px; z-index: 10;
}
.filter-group { display: flex; flex-direction: column; gap: 2px; min-width: 130px; flex: 1; }
.filter-group label { font-size: 0.88rem; color: var(--muted); }
.search-group { flex: 2.2; min-width: 220px; }
.search-wrap { position: relative; }
.search-wrap svg { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--muted); pointer-events: none; }
.search-wrap input {
  width: 100%; border: 1px solid var(--line); border-radius: 8px;
  padding: 7px 10px 7px 32px; font-size: 0.9rem; background: #fff; color: var(--ink);
}
.search-wrap input:focus { outline: 2px solid var(--accent); border-color: var(--accent); }
.result-count { color: var(--muted); font-size: 0.8rem; margin: 0 2px 10px; }
.filter-group select {
  border: 1px solid var(--line); border-radius: 8px; padding: 7px 8px; font-size: 0.88rem;
  background: #fff; color: var(--ink); width: 100%;
}

/* Grade range on a learning-stage card: quieter than the stage name, so the
   card reads "文法阶段 K-G6" as one line with the range as a qualifier. It is
   what a parent unfamiliar with the trivium actually navigates by. */
.choice-card h3 .stage-range {
  font-size: 0.82rem; font-weight: 500; color: var(--muted);
  background: var(--bg); border: 1px solid var(--line);
  border-radius: 999px; padding: 1px 8px; margin-left: 6px; white-space: nowrap;
}

/* Grade multi-select: a select-looking button over a checkbox panel, so a
   parent can pick G1, G3 and G5 at once. Styled to match .filter-group select
   exactly when closed, so the filter bar still reads as one row of controls. */
.ms-group { position: relative; }
.ms-btn {
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  border: 1px solid var(--line); border-radius: 8px; padding: 7px 8px; font-size: 0.88rem;
  background: #fff; color: var(--ink); width: 100%; cursor: pointer; text-align: left;
  font-family: inherit; line-height: 1.4;
}
.ms-btn:hover { border-color: var(--accent); }
.ms-btn:focus-visible { outline: 2px solid var(--accent); border-color: var(--accent); }
.ms-btn-txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ms-caret { color: var(--muted); font-size: 0.75rem; flex: none; }
.ms-panel {
  position: absolute; top: 100%; left: 0; right: 0; margin-top: 4px; z-index: 30;
  background: var(--card); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.14);
  max-height: 320px; overflow-y: auto; padding: 6px; min-width: 190px;
}
.ms-stage { padding: 2px 0; }
.ms-stage + .ms-stage { border-top: 1px solid var(--line); margin-top: 4px; padding-top: 6px; }
.ms-row {
  display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 6px;
  font-size: 0.88rem; cursor: pointer; user-select: none;
}
.ms-row:hover { background: var(--bg); }
.ms-row input { accent-color: var(--accent); width: 15px; height: 15px; flex: none; cursor: pointer; }
.ms-foot { border-top: 1px solid var(--line); margin-top: 4px; padding: 6px 4px 2px; text-align: right; }
.ms-clear {
  border: 0; background: none; color: var(--accent); font-size: 0.82rem; cursor: pointer;
  padding: 4px 6px; border-radius: 6px; font-family: inherit;
}
.ms-clear:hover { background: var(--bg); }

/* Course cards (compact) */
.choice-grid-2 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); max-width: 720px; }
.course-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); gap: 18px; }
.course-card {
  background: var(--card); border: 2px solid var(--line); border-radius: var(--radius);
  padding: 22px; cursor: pointer; box-shadow: var(--shadow); position: relative;
  display: flex; flex-direction: column; gap: 11px;
  transition: border-color 0.15s, transform 0.15s, box-shadow 0.15s;
}
.course-card:hover {
  border-color: #8fa8c2; transform: translateY(-2px);
  box-shadow: 0 2px 6px rgba(30, 41, 59, 0.1), 0 10px 24px rgba(30, 41, 59, 0.09);
}
.course-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.course-card.selected { border-color: var(--accent); background: var(--accent-soft); }
.course-card .top { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; }
.course-card h4 { margin: 0; font-size: 0.98rem; line-height: 1.4; }
.course-card .code { color: var(--muted); font-size: 0.74rem; letter-spacing: 0.04em; margin-top: 1px; }
.expand-ic {
  width: 26px; height: 26px; border-radius: 8px; flex: none;
  display: grid; place-items: center; color: var(--muted);
  background: #eef1f6; transition: background 0.15s, color 0.15s;
}
.course-card:hover .expand-ic { background: var(--accent); color: #fff; }
.tag-row { display: flex; flex-wrap: wrap; gap: 6px; }
.tag {
  font-size: 0.72rem; padding: 2px 9px; border-radius: 999px;
  background: #eef1f6; color: var(--accent-dark); border: 1px solid var(--line);
}
/* Compact card content: no field-label chrome — name, chips, teacher, schedule */
.code-inline { font-weight: 400; color: var(--muted); font-size: 0.76rem; letter-spacing: 0.03em; }
.course-desc {
  color: var(--muted); font-size: 0.89rem; margin: 0; line-height: 1.55;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.more-hint { color: var(--accent-dark); font-size: 0.84rem; font-weight: 600; }
.teachers-line { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }

/* Meta chips: live/recorded + grades, the "what & who" at a glance */
.chip-row { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 0.72rem; font-weight: 600; padding: 3px 9px; border-radius: 999px;
  border: 1px solid transparent;
}
/* Same neutral chip for both kinds of metadata — the icon carries the meaning
   (a solid dot for live, a filmstrip for recorded), not a wash of color. */
.chip-type, .chip-grade { background: #eef1f6; color: var(--ink); border-color: var(--line); }
.chip-grade { font-variant-numeric: tabular-nums; color: var(--muted); }
.chip-type.live svg { color: var(--accent); }
.chip-type.recorded svg { color: var(--muted); }

.card-line { display: flex; align-items: center; gap: 6px; font-size: 0.84rem; color: var(--muted); flex-wrap: wrap; }
.card-line svg { flex: none; color: var(--muted); }
.teacher-line svg { color: var(--accent); }
.sched-line svg { color: var(--accent); }
.t-link {
  background: none; border: none; padding: 0; cursor: pointer; font: inherit; font-size: 0.86rem;
  color: var(--ink); font-weight: 600;
  border-bottom: 1px dashed var(--muted); line-height: 1.35;
}
.t-link:hover { color: var(--accent-dark); border-bottom-color: var(--accent); }
.t-link.plain, span.t-link.plain { border-bottom: none; cursor: default; color: var(--muted); font-weight: 500; }
.course-bottom { margin-top: auto; display: flex; justify-content: space-between; align-items: center; gap: 10px; padding-top: 2px; }
.price { font-weight: 800; color: var(--accent-dark); font-size: 1.08rem; font-variant-numeric: tabular-nums; }
.price.big { font-size: 1.35rem; }
.price.tbd { color: var(--muted); font-weight: 600; font-size: 0.85rem; }
.d-value .tbd { color: var(--muted); font-style: italic; }
/* An empty course description shows a quiet "coming soon" placeholder. */
.desc-tbd { color: var(--muted); font-style: italic; }
.btn-select {
  border: 2px solid var(--accent); background: #fff; color: var(--accent-dark);
  border-radius: 999px; padding: 7px 20px; font-size: 0.88rem; font-weight: 700;
  cursor: pointer; transition: background 0.15s, color 0.15s;
}
.btn-select:hover { background: var(--accent-soft); }
.btn-select.on { background: var(--accent); color: #fff; }
.btn-select.lg { padding: 10px 30px; font-size: 0.98rem; }

/* Modals */
body.modal-open { overflow: hidden; }
.modal-overlay {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(30, 41, 59, 0.45);
  display: flex; align-items: center; justify-content: center;
  padding: 22px; opacity: 0; transition: opacity 0.18s ease;
}
.modal-overlay.show { opacity: 1; }
.modal {
  background: var(--card); border-radius: 18px; box-shadow: 0 20px 60px rgba(30, 41, 59, 0.3);
  width: 100%; max-width: 760px; max-height: min(90vh, 860px);
  display: flex; flex-direction: column; position: relative;
  transform: translateY(14px) scale(0.985); transition: transform 0.18s ease;
  overflow: hidden;
}
.modal-overlay.show .modal { transform: none; }
.modal-x {
  position: absolute; top: 12px; right: 12px; z-index: 2;
  width: 34px; height: 34px; border-radius: 50%; border: none; cursor: pointer;
  background: #eef1f6; color: var(--muted); font-size: 0.95rem; font-weight: 700;
}
.modal-x:hover { background: var(--accent); color: #fff; }
.modal-head { padding: 26px 60px 14px 28px; border-bottom: 1px solid var(--line); }
.modal-head h3 { margin: 0 0 2px; font-size: 1.1rem; line-height: 1.35; }
.modal-head .code { color: var(--muted); font-size: 0.78rem; letter-spacing: 0.04em; margin-bottom: 8px; }
.modal-body { padding: 20px 28px; overflow-y: auto; }
.modal-foot {
  padding: 16px 28px; border-top: 1px solid var(--line);
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  background: #f5f7fa;
}
.d-desc { margin-bottom: 14px; }
.d-desc p { margin: 4px 0 0; color: var(--ink); font-size: 0.92rem; }
/* Field labels read at least as large as their values (per review feedback —
   a label smaller than its value looked wrong, e.g. 授课语言 under 英语). */
.d-label { font-size: 0.92rem; font-weight: 700; color: var(--muted); letter-spacing: 0.03em; }
.d-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 20px; }
.d-row { min-width: 0; }
.d-value { font-size: 0.92rem; margin-top: 2px; overflow-wrap: break-word; }
.d-value .muted { color: var(--muted); font-size: 0.82rem; }
.d-grid .d-row.wide { grid-column: 1 / -1; }
.sched-chip {
  display: inline-block; background: #eef1f6; border: 1px solid var(--line);
  border-radius: 8px; padding: 3px 10px; margin: 2px 6px 2px 0; font-size: 0.84rem;
}
/* The weekday chip leads the schedule row, so it reads a step stronger than
   the individual class times that follow it. */
.sched-chip.sched-days {
  background: #e8eef5; border-color: #c3d2e0; font-weight: 600;
}
.tb-item { padding: 3px 0; font-size: 0.9rem; }
.tb-price { color: var(--accent-dark); font-weight: 700; margin-left: 6px; }
.syl-link {
  display: inline-flex; align-items: center; gap: 6px; margin: 2px 12px 2px 0;
  color: var(--accent-dark); font-weight: 600; font-size: 0.88rem; text-decoration: none;
  border-bottom: 1px dashed var(--accent);
}
.syl-link:hover { color: var(--accent); }
.t-chip {
  display: inline-flex; align-items: center; margin: 2px 8px 2px 0;
  background: #eef1f6; color: var(--ink); border: 1px solid var(--line);
  border-radius: 999px; padding: 4px 14px; font-size: 0.86rem; font-weight: 600; cursor: pointer;
}
.t-chip:hover { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-dark); }
span.t-chip.plain { background: #eef1f6; border-color: var(--line); color: var(--muted); cursor: default; }

/* Teacher modal */
.teacher-modal { max-width: 520px; }
.t-head { display: flex; gap: 18px; align-items: center; padding: 24px 56px 16px 24px; border-bottom: 1px solid var(--line); }
.t-photo {
  width: 84px; height: 84px; border-radius: 50%; object-fit: cover; object-position: top;
  flex: none; border: 3px solid var(--accent-soft); box-shadow: var(--shadow);
}
.t-photo-fallback {
  display: grid; place-items: center; background: var(--accent-soft);
  color: var(--accent-dark); font-size: 2rem; font-weight: 800;
}
.t-kicker { font-size: 0.72rem; font-weight: 700; color: var(--accent-dark); text-transform: uppercase; letter-spacing: 0.08em; }
.t-head h3 { margin: 2px 0; font-size: 1.1rem; }
.t-org { color: var(--muted); font-size: 0.88rem; }
.t-bio { margin: 0 0 14px; font-size: 0.92rem; white-space: pre-wrap; }
.t-expertise { margin-bottom: 14px; }
.t-expertise p { margin: 4px 0 0; font-size: 0.9rem; color: var(--ink); white-space: pre-wrap; }
.t-attrs { display: grid; grid-template-columns: 1fr; gap: 8px; }
.t-attr { display: flex; gap: 10px; font-size: 0.88rem; }
.t-attr-label { flex: none; min-width: 92px; color: var(--muted); font-weight: 600; }

/* Cart bar */
.cart-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
  background: #1e293b; color: #fff; padding: 12px 20px;
  display: none; justify-content: center;
}
.cart-bar.visible { display: flex; }
.cart-inner { max-width: 1080px; width: 100%; display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.cart-info { flex: 1; font-size: 0.95rem; }
.cart-info b { color: #f0b84a; }

/* Buttons */
.btn {
  border: none; border-radius: 10px; padding: 11px 26px; font-size: 0.95rem; font-weight: 600;
  cursor: pointer; transition: opacity 0.15s;
}
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover:not(:disabled) { background: var(--accent-dark); }
.btn-ghost { background: transparent; color: var(--muted); border: 1px solid var(--line); }
.btn-ghost:hover { color: var(--ink); border-color: var(--muted); }
.nav-row { display: flex; justify-content: space-between; margin-top: 28px; gap: 12px; }

/* Order form */
.order-layout { display: grid; grid-template-columns: 1.4fr 1fr; gap: 20px; align-items: start; }
@media (max-width: 780px) { .order-layout { grid-template-columns: 1fr; } }
.summary-card, .form-card {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 18px 20px; box-shadow: var(--shadow);
}
.summary-card h3, .form-card h3 { margin: 0 0 12px; font-size: 1rem; }
.summary-item { display: flex; justify-content: space-between; gap: 10px; padding: 8px 0; border-bottom: 1px dashed var(--line); font-size: 0.9rem; }
.summary-item:last-of-type { border-bottom: none; }
/* Removing a course from the cart is a neutral action, not a rejection —
   plain muted text rather than the error color. */
.summary-item .rm { color: var(--muted); background: none; border: none; cursor: pointer; font-size: 0.8rem; padding: 0 4px; text-decoration: underline; text-decoration-style: dashed; }
.summary-item .rm:hover { color: var(--accent-dark); }
.summary-total { display: flex; justify-content: space-between; font-weight: 800; padding-top: 12px; border-top: 2px solid var(--line); margin-top: 6px; }
.form-card label { display: block; font-size: 0.95rem; font-weight: 600; margin: 14px 0 4px; }
.form-card input {
  width: 100%; border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px; font-size: 0.95rem;
  background: #fff; color: var(--ink);
}
.form-card input:focus { outline: 2px solid var(--accent); border-color: var(--accent); }
.field-note { margin: 6px 0 0; color: var(--muted); font-size: 0.78rem; line-height: 1.5; }
.hp { position: absolute; left: -9999px; top: -9999px; height: 0; width: 0; overflow: hidden; }
.form-err { color: var(--err); font-size: 0.85rem; margin: 10px 0 0; min-height: 1.2em; }

/* Confirmation */
.done-card {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 48px 24px; text-align: center; box-shadow: var(--shadow); max-width: 560px; margin: 40px auto;
}
.done-card .mark { width: 64px; height: 64px; margin: 0 auto 16px; color: var(--ok); }
.done-card h2 { margin: 0 0 8px; font-size: 1.25rem; }
.done-card p { color: var(--muted); }
.order-id {
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 1.05rem; font-weight: 700;
  background: var(--accent-soft); color: var(--accent-dark); border-radius: 10px;
  display: inline-block; padding: 8px 18px; margin: 10px 0 22px;
}

/* Misc */
.notice { text-align: center; color: var(--muted); padding: 60px 12px; }
.hidden { display: none !important; }
@media (max-width: 640px) {
  .stepper { font-size: 0.75rem; }
  .step-item span.lbl { display: none; }
  .step-item.active span.lbl { display: inline; }
  .filter-bar { position: static; }
  /* modals become bottom sheets on phones */
  .modal-overlay { padding: 0; align-items: flex-end; }
  .modal {
    max-width: none; border-radius: 18px 18px 0 0; max-height: 88vh;
    transform: translateY(40px);
  }
  .d-grid { grid-template-columns: 1fr; }
  .t-head { padding: 20px 56px 14px 18px; }
  .modal-head { padding: 20px 56px 10px 18px; }
  .modal-body { padding: 14px 18px; }
  .modal-foot { padding: 12px 18px; }
}

/* ---------- curriculum map (step 6) ---------- */
/* Subjects down, grades across; the parent's own table from Airtable. Cells
   are buttons into a detail sheet, so the grid itself stays short: three
   planned items, a "+N" pill for the rest, and a green count of the catalog
   courses that fit. Two renderings live in the DOM — the table for wide
   screens, a grade-tab list for phones — and the media query picks one. */
.cm-scope { font-size: 0.8rem; font-weight: 600; color: var(--accent); background: var(--accent-soft); border-radius: 999px; padding: 3px 12px; vertical-align: middle; margin-left: 8px; }
.cm-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden; }
.cm-scroll { overflow-x: auto; }
.cm-table { width: 100%; min-width: 760px; border-collapse: separate; border-spacing: 0; table-layout: fixed; font-size: 0.86rem; }
.cm-table th, .cm-table td { border-bottom: 1px solid var(--line); vertical-align: top; text-align: left; }
.cm-table tbody tr:last-child th, .cm-table tbody tr:last-child td { border-bottom: none; }
.cm-table thead th { position: sticky; top: 0; z-index: 2; background: var(--card); padding: 12px 12px 10px; color: var(--accent); font-weight: 700; font-size: 0.9rem; border-bottom: 2px solid var(--line); }
.cm-table thead th:not(.cm-corner)::after { content: ""; display: block; height: 3px; margin-top: 8px; border-radius: 2px; background: var(--accent); }
.cm-corner, .cm-row { width: 150px; }
.cm-row { position: sticky; left: 0; z-index: 1; background: var(--card); padding: 12px; font-weight: 700; font-size: 0.9rem; border-right: 1px solid var(--line); }
.cm-table td { padding: 10px 10px 12px; line-height: 1.45; }
.cm-cell { cursor: pointer; transition: background 0.12s; }
.cm-cell:hover, .cm-cell:focus-visible { background: var(--accent-soft); outline: none; }
.cm-none { background: repeating-linear-gradient(135deg, transparent 0 6px, #f1f3f7 6px 7px); }
.cm-span { background: #fafbfd; }
.cm-span .cm-item { display: inline; margin: 0; }
.cm-span .cm-item + .cm-item::before { content: " · "; color: var(--muted); }
.cm-item { margin: 0 0 4px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.cm-more { display: inline-block; margin: 2px 6px 0 0; border: 1px solid var(--line); border-radius: 999px; padding: 0 9px; font-size: 0.78rem; font-weight: 600; color: var(--accent); background: var(--card); }
.cm-avail { display: inline-flex; align-items: center; gap: 6px; margin-top: 6px; border-radius: 999px; padding: 2px 10px 2px 8px; font-size: 0.78rem; font-weight: 600; color: var(--ok); background: #eaf6ee; white-space: nowrap; }
.cm-avail::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--ok); }
/* phone view */
.cm-mobile { display: none; }
.cm-tabs { display: flex; gap: 6px; overflow-x: auto; padding: 12px 12px 10px; border-bottom: 1px solid var(--line); scrollbar-width: none; }
.cm-tabs::-webkit-scrollbar { display: none; }
.cm-tab { flex: 0 0 auto; border: 1px solid var(--line); background: var(--card); border-radius: 999px; padding: 6px 14px; font: inherit; font-weight: 600; font-size: 0.9rem; color: var(--muted); cursor: pointer; }
.cm-tab.on { background: var(--accent); color: #fff; border-color: var(--accent); }
.cm-mrow { padding: 12px 14px; border-bottom: 1px solid var(--line); }
.cm-mrow:last-child { border-bottom: none; }
.cm-mrow h4 { margin: 0 0 4px; font-size: 0.95rem; }
.cm-mrow .cm-item { font-size: 0.9rem; -webkit-line-clamp: 3; }
.cm-none-msg { padding: 18px 14px; color: var(--muted); }
@media (max-width: 720px) {
  .cm-scroll { display: none; }
  .cm-mobile { display: block; }
}
/* the cell's detail sheet */
.cm-sheet { max-width: 640px; }
.cm-sheet-h { margin: 0 0 8px; font-size: 0.8rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.cm-sheet-h + .cm-sheet-h, .cm-sheet-items + .cm-sheet-h, .cm-sheet-none + .cm-sheet-h, .cm-sheet-courses + .cm-sheet-h { margin-top: 22px; }
.cm-sheet-items { margin: 0; padding-left: 2.4em; line-height: 1.55; }
.cm-sheet-items li { margin-bottom: 4px; }
.cm-sheet-none { margin: 0; color: var(--muted); }
.cm-sheet-courses { display: flex; flex-direction: column; gap: 8px; }
.cm-sheet-course { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px; }
.cm-sheet-name { border: none; background: none; padding: 0; font: inherit; font-weight: 600; color: var(--ink); text-align: left; cursor: pointer; }
.cm-sheet-name:hover { color: var(--accent); }
.cm-sheet-code { display: block; font-weight: 400; font-size: 0.78rem; color: var(--muted); }
.btn-select.sm { padding: 6px 14px; font-size: 0.85rem; flex: 0 0 auto; }

/* ---------- cart bar summary + cart sheet ---------- */
/* The bar's summary is a button: it opens the cart sheet. Styled as the text
   it always was, plus a quiet "查看 ›" so it reads as tappable. */
button.cart-info {
  background: none; border: none; color: inherit; font: inherit; text-align: left;
  padding: 6px 10px; margin: -6px -10px; border-radius: 8px; cursor: pointer;
}
button.cart-info:hover, button.cart-info:focus-visible { background: rgba(255, 255, 255, 0.08); outline: none; }
.cart-view { margin-left: 10px; font-size: 0.85rem; color: #cbd5e1; }
.cart-sheet { max-width: 560px; }
.cart-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--line); }
.cart-row:last-child { border-bottom: none; }
.cart-row-right { display: flex; align-items: center; gap: 12px; flex: 0 0 auto; }
.cart-price { font-weight: 600; font-variant-numeric: tabular-nums; }
.cart-sheet .rm { background: none; border: none; color: var(--muted); font: inherit; font-size: 0.85rem; cursor: pointer; text-decoration: underline; }
.cart-sheet .rm:hover { color: var(--ink); }
.cart-total { font-size: 0.95rem; }
.cart-total b { font-size: 1.05rem; }
