/*
Theme Name: Hanlin Portal Base
Theme URI: https://github.com/meimouren/wordpress-site-builder
Author: Hanlin Education
Author URI: https://github.com/meimouren/wordpress-site-builder
Description: Neutral FSE block theme baseline used by the wordpress-site-builder skill. Ships architecture only — no project-specific palette, copy, chrome, or shortcode body. Each project sets its design via /design-brief and applies it via /build-chrome (parts/header.html + parts/footer.html + chrome.css). Bakes in 90+ lessons from production projects (see docs/lessons-learned.md): pre_get_document_title bypass for wptexturize, dynamic blocks (avoid wpautop), self-hosted fonts + Material Symbols subset, FSE templates, REST binary upload for theme files, admin Site Tools panel (verification meta + analytics + QR), L88 is_home/is_front_page handling, L90 admin bar offset, etc.
Version: 2.0.0
Requires at least: 6.4
Tested up to: 6.6
Requires PHP: 7.4
License: GPL v2 or later
Text Domain: hl-baseline
Tags: full-site-editing, block-styles, education, blog, news, neutral
*/

/* ==========================================================================
   1. Base reset + global
   ========================================================================== */

@import url("assets/fonts.css");

html { scroll-behavior: smooth; }

body,
.wp-site-blocks { overflow-x: clip; }

body {
  background-color: var(--wp--preset--color--background, #F7F9FB);
  color: var(--wp--preset--color--body, #44474B);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-family: var(--wp--preset--font-family--sans-cjk, "Noto Sans SC"), -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", "Hiragino Sans GB", sans-serif;
}

img,
video {
  max-width: 100%;
  height: auto;
  display: block;
}

a { transition: color 0.2s ease, background-color 0.2s ease, opacity 0.2s ease; }

/* ==========================================================================
   2. Heading size constraints (mobile)
   ========================================================================== */

@media (max-width: 880px) {
  h1.wp-block-heading { font-size: 36px !important; line-height: 1.25 !important; }
  h2.wp-block-heading { font-size: 24px !important; line-height: 1.3 !important; }
  h3.wp-block-heading { font-size: 20px !important; }
}

/* ==========================================================================
   3. WP global padding reset — let template-parts edge-to-edge
   ========================================================================== */

body.wp-site-blocks,
body,
.wp-site-blocks {
  --wp--style--root--padding-top:    0 !important;
  --wp--style--root--padding-bottom: 0 !important;
  --wp--style--root--padding-left:   0 !important;
  --wp--style--root--padding-right:  0 !important;
  --wp--style--block-gap:            0 !important;
}

/* 🔴 L115: This rule strips margin/padding-top|bottom from ALL direct children of
   .wp-site-blocks (every block at the top level of a template: header, wp:html,
   wp:group, etc.). Its purpose is to prevent WP from inserting default block-gap
   between template sections.
   CONSEQUENCE FOR PROJECT CSS: any padding/margin you put on a block that is a
   direct child of .wp-site-blocks (e.g. a <header> inside wp:html, or main.wp:group)
   will be silently zeroed by this rule — even if you write padding:52px in project CSS.
   CORRECT PATTERN: put vertical spacing on an INNER element (one level down), not on
   the block root itself. E.g. for a hero section: .hero{background:...} (no padding),
   .hero-wrap{padding:52px 28px 44px} (padding on the inner container). */
.wp-site-blocks > *,
.wp-site-blocks > .wp-block-template-part {
  margin-top: 0 !important;
  margin-bottom: 0 !important;
  padding-top: 0 !important;
  padding-bottom: 0 !important;
}

.wp-block-template-part {
  margin: 0 !important;
  padding: 0 !important;
}

/* ==========================================================================
   4. WP page content container reset — let project section HTML self-own width
       Removes:
       - has-global-padding side effects
       - is-layout-constrained / is-layout-flow auto margins
       - is-layout-flow blockGap (the cause of stray white rows between sections)

   🔴 L111: SCOPED TO body.page ONLY. This reset exists for the full-bleed PAGE
   workflow (pages are full-bleed wp:html whose own *-wrap sections own the width).
   It must NOT apply to single posts / archives — otherwise it force-flattens any
   styled article reading column to full-width with !important, a trap every project
   that styles a single.html otherwise rediscovers. Single posts (body.single) and
   archives keep normal block width so article templates can build a constrained
   reading column / two-column layout.
   ========================================================================== */

body.page .wp-block-post-content,
body.page .wp-block-post-content.has-global-padding,
body.page .wp-block-post-content.is-layout-constrained,
body.page main.wp-block-group.is-layout-flow {
  padding-left: 0 !important;
  padding-right: 0 !important;
  padding-top: 0 !important;
  padding-bottom: 0 !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
  margin-top: 0 !important;
  margin-bottom: 0 !important;
  max-width: 100% !important;
  --wp--style--block-gap: 0 !important;
}

body.page .wp-block-post-content > *,
body.page .wp-block-post-content > section,
body.page main.wp-block-group > *,
body.page main.wp-block-group > .wp-block-post-content,
body.page main.wp-block-group.is-layout-flow > * {
  margin-top: 0 !important;
  margin-bottom: 0 !important;
  margin-block: 0 !important;
}

body.page .wp-block-post-content > section {
  width: 100%;
  max-width: 100%;
  margin-left: 0;
  margin-right: 0;
}

/* ==========================================================================
   5. Full-bleed banner utility (used by project HTML for hero sections)
   ========================================================================== */

.hl-banner-fullbleed {
  width: 100%;
  max-width: 100%;
  margin-left: 0;
  margin-right: 0;
  box-sizing: border-box;
}

/* ==========================================================================
   6. Section background utility classes (neutral · projects override colors)
   ========================================================================== */

.hl-section-white { background-color: var(--wp--preset--color--surface, #FFFFFF); }
.hl-section-soft  { background-color: var(--wp--preset--color--surface-alt, #F2F4F6); }
.hl-section-bg    { background-color: var(--wp--preset--color--background, #F7F9FB); }
.hl-section-ink   { background-color: var(--wp--preset--color--ink, #0F172A); color: var(--wp--preset--color--surface, #FFFFFF); }

/* ==========================================================================
   7. Long-form article prose · .hl-prose
       Used for legal pages / privacy / about copy / blog post bodies.
       Neutral colors — projects can override via project chrome.css.
   ========================================================================== */

.hl-prose {
  font-family: var(--wp--preset--font-family--sans-cjk, "Noto Sans SC"), -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif;
  font-size: 17px;
  color: var(--wp--preset--color--heading, #1A1C1E);
  line-height: 1.85;
  letter-spacing: 0.01em;
}

.hl-prose p {
  margin: 0 0 1.5rem;
  color: var(--wp--preset--color--heading, #1A1C1E);
}

.hl-prose h2 {
  font-family: inherit;
  font-size: 26px;
  font-weight: 700;
  color: var(--wp--preset--color--heading, #1A1C1E);
  line-height: 1.4;
  margin: 3rem 0 1.25rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--wp--preset--color--border, #E2E8F0);
}

.hl-prose h2:first-child,
.hl-prose > p:first-child + h2 { margin-top: 1rem; }

.hl-prose h3 {
  font-family: inherit;
  font-size: 20px;
  font-weight: 600;
  color: var(--wp--preset--color--heading, #1A1C1E);
  line-height: 1.4;
  margin: 2rem 0 0.75rem;
}

.hl-prose h4 {
  font-family: inherit;
  font-size: 17px;
  font-weight: 600;
  color: var(--wp--preset--color--heading, #1A1C1E);
  margin: 1.5rem 0 0.5rem;
}

.hl-prose ul,
.hl-prose ol {
  margin: 0 0 1.5rem;
  padding-left: 1.75rem;
}

.hl-prose ul { list-style: disc; }
.hl-prose ol { list-style: decimal; }

.hl-prose ul li::marker { color: var(--wp--preset--color--accent, #2563EB); }
.hl-prose ol li::marker { color: var(--wp--preset--color--accent, #2563EB); font-weight: 700; }

.hl-prose li {
  margin-bottom: 0.6rem;
  line-height: 1.8;
  padding-left: 0.25rem;
}

.hl-prose li > ul,
.hl-prose li > ol { margin: 0.5rem 0; }

.hl-prose strong { color: var(--wp--preset--color--heading, #1A1C1E); font-weight: 700; }

.hl-prose em { font-style: italic; color: var(--wp--preset--color--body, #44474B); }

.hl-prose a {
  color: var(--wp--preset--color--accent, #2563EB);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
  transition: color 0.2s, text-decoration-color 0.2s;
  font-weight: 600;
}

.hl-prose a:hover {
  color: var(--wp--preset--color--heading, #1A1C1E);
  text-decoration-color: var(--wp--preset--color--heading, #1A1C1E);
}

.hl-prose blockquote {
  border-left: 4px solid var(--wp--preset--color--accent, #2563EB);
  padding: 1.5rem 1.75rem;
  margin: 2rem 0;
  background-color: var(--wp--preset--color--surface-alt, #F2F4F6);
  border-radius: 0 8px 8px 0;
  font-style: italic;
  color: var(--wp--preset--color--heading, #1A1C1E);
  font-size: 16px;
  line-height: 1.75;
}

.hl-prose blockquote p { margin: 0; }
.hl-prose blockquote p + p { margin-top: 0.75rem; }

.hl-prose hr {
  border: 0;
  height: 1px;
  background: linear-gradient(to right, transparent, var(--wp--preset--color--border, #E2E8F0) 20%, var(--wp--preset--color--border, #E2E8F0) 80%, transparent);
  margin: 3rem 0;
}

.hl-prose code {
  font-family: "SF Mono", Consolas, Monaco, monospace;
  background-color: var(--wp--preset--color--surface-alt, #F2F4F6);
  color: var(--wp--preset--color--accent, #2563EB);
  padding: 2px 6px;
  border-radius: 4px;
  font-size: 0.9em;
  border: 1px solid var(--wp--preset--color--border, #E2E8F0);
}

.hl-prose pre {
  background: var(--wp--preset--color--ink, #0F172A);
  color: var(--wp--preset--color--surface, #FFFFFF);
  padding: 1.5rem;
  border-radius: 8px;
  overflow-x: auto;
  margin: 1.5rem 0;
  font-size: 14px;
  line-height: 1.6;
}

.hl-prose pre code {
  background: none;
  color: inherit;
  border: 0;
  padding: 0;
}

.hl-prose table {
  width: 100%;
  border-collapse: collapse;
  margin: 1.5rem 0;
  font-size: 15px;
}

.hl-prose th,
.hl-prose td {
  padding: 0.85rem 1rem;
  border: 1px solid var(--wp--preset--color--border, #E2E8F0);
  text-align: left;
  vertical-align: top;
}

.hl-prose th {
  background: var(--wp--preset--color--ink, #0F172A);
  color: #fff;
  font-weight: 700;
  font-family: var(--wp--preset--font-family--inter, "Inter"), "Noto Sans SC", sans-serif;
  font-size: 14px;
  letter-spacing: 0.04em;
}

.hl-prose tr:nth-child(even) td {
  background: var(--wp--preset--color--background, #F7F9FB);
}

/* First paragraph as "updated on: ..." meta · weakened style.
   🔴 L114: SCOPED TO body.page ONLY. On legal/about PAGES the first prose paragraph
   is a "Last updated: …" caption (weakened + separator). It must NOT apply to single
   POSTS — there the first paragraph is the article LEAD, and this rule would shrink it
   to 14px gray + add a stray hairline. Same trap family as L111/L112 (page-workflow
   rule leaking onto posts). Articles style their own lead via the project prose class. */
body.page .hl-prose > p:first-child {
  color: var(--wp--preset--color--muted, #75777C) !important;
  font-size: 14px !important;
  margin-bottom: 2rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--wp--preset--color--border, #E2E8F0);
}

@media (max-width: 640px) {
  .hl-prose { font-size: 16px; line-height: 1.8; }
  .hl-prose h2 { font-size: 22px; margin-top: 2.25rem; }
  .hl-prose h3 { font-size: 18px; }
}

/* ==========================================================================
   8. Section underline (decorative · projects can override color)
   ========================================================================== */

.hl-section-underline {
  width: 64px;
  height: 4px;
  border-radius: 2px;
  background-color: var(--wp--preset--color--accent, #2563EB);
  margin: 0 auto;
}

/* ==========================================================================
   9. Floating TOC · left-gutter overlay (L110 · behavior locked in theme.js)
      - position:fixed overlay in the reading column's LEFT gutter — it never
        participates in content width and never shifts the prose (user spec:
        「不要计算到正文的宽度中，不要影响正文的排版」)
      - anchored to a 760px centered reading column via calc():
          column left edge   = 50% - 380px
          TOC right edge sits 28px to its left → left = 50% - 380 - width - 28
      - element + auto-gen + scrollspy + show/hide range all driven by theme.js
        (.is-hidden fades it out outside the article body range)
      - shown only ≥ 1240px (narrower viewports have no gutter room → hidden)
      - all colors via theme.json CSS vars; projects restyle via chrome.css
   ========================================================================== */

.hl-toc-float {
  --hl-toc-width: 200px;
  --hl-reading-half: 380px; /* half of the 760px reading column */
  display: none;            /* shown by the ≥1240px media query below */
  position: fixed;
  top: 120px;
  left: calc(50% - var(--hl-reading-half) - var(--hl-toc-width) - 28px);
  width: var(--hl-toc-width);
  max-height: calc(100vh - 180px);
  overflow-y: auto;
  z-index: 40;
  padding: 4px 0;
  transition: opacity 0.3s ease;
  opacity: 1;
}

/* JS adds .is-hidden when scrolled above the article body or past its end */
.hl-toc-float.is-hidden {
  opacity: 0;
  pointer-events: none;
}

.hl-toc-head {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--wp--preset--color--muted, #75777C);
  margin: 0 0 12px;
  padding-left: 14px;
}

.hl-toc-list { list-style: none; padding: 0; margin: 0; }

.hl-toc-item {
  margin: 2px 0;
  border-left: 2px solid var(--wp--preset--color--border, #E2E8F0);
  transition: border-color 0.2s ease;
}
.hl-toc-item.hl-toc-h3 { padding-left: 14px; }

.hl-toc-item a {
  display: block;
  color: var(--wp--preset--color--body, #44474B);
  opacity: 0.7;
  text-decoration: none;
  font-size: 12.5px;
  line-height: 1.4;
  padding: 5px 0 5px 14px;
  transition: color 0.15s ease, opacity 0.15s ease;
}
.hl-toc-item a:hover { color: var(--wp--preset--color--heading, #1A1C1E); opacity: 1; }

/* Scrollspy active state — accent border + bold (border on same side as the
   container rail so it's always visible · F18 / L54 defense) */
.hl-toc-item.is-active {
  border-left-color: var(--wp--preset--color--accent, #2563EB);
}
.hl-toc-item.is-active > a {
  color: var(--wp--preset--color--heading, #1A1C1E);
  opacity: 1;
  font-weight: 700;
}

/* thin, hover-only scrollbar (F18 defense — no permanent thumb) */
.hl-toc-float { scrollbar-width: thin; scrollbar-color: transparent transparent; }
.hl-toc-float::-webkit-scrollbar { width: 4px; }
.hl-toc-float::-webkit-scrollbar-thumb { background: transparent; border-radius: 2px; }
.hl-toc-float:hover::-webkit-scrollbar-thumb { background: var(--wp--preset--color--border, #E2E8F0); }

@media (min-width: 1240px) {
  .hl-toc-float { display: block; }
}

/* ==========================================================================
   10. Back to top button · neutral, projects override colors
   ========================================================================== */

.hl-back-to-top {
  position: fixed;
  right: 24px;
  bottom: 24px;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--wp--preset--color--ink, #0F172A);
  color: var(--wp--preset--color--surface, #FFFFFF);
  border: 0;
  cursor: pointer;
  display: none;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  z-index: 40;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  transition: opacity 0.3s, transform 0.2s;
}

.hl-back-to-top:hover { transform: translateY(-2px); }
.hl-back-to-top.is-visible { display: inline-flex; }

/* ==========================================================================
   10b. Contact CTA card (L119) · .hl-article-cta
        Auto-injected on post detail (functions.php §17) + [hl_contact_cta].
        Neutral / CSS-var driven; projects restyle via chrome.css. All copy /
        QR / button come from Site Tools — never hardcoded in page HTML.
   ========================================================================== */

.hl-article-cta {
  display: flex;
  flex-direction: column;
  gap: 24px;
  background: var(--wp--preset--color--ink, #0F172A);
  color: var(--wp--preset--color--surface, #FFFFFF);
  border-radius: 16px;
  padding: 28px;
  margin: 40px 0;
}
.hl-article-cta-body { flex: 1; min-width: 0; }
.hl-article-cta-title { margin: 0 0 8px; font-size: 22px; font-weight: 800; line-height: 1.2; color: #fff; }
.hl-article-cta-sub { margin: 0 0 14px; font-size: 14px; line-height: 1.5; opacity: 0.82; }
.hl-article-cta-bullets { list-style: none; padding: 0; margin: 0 0 16px; font-size: 13px; line-height: 1.6; opacity: 0.92; }
.hl-article-cta-bullets li { position: relative; padding-left: 18px; margin-bottom: 4px; }
.hl-article-cta-bullets li::before { content: "\2713"; position: absolute; left: 0; color: var(--wp--preset--color--accent, #2563EB); font-weight: 700; }
.hl-article-cta-qr { flex-shrink: 0; text-align: center; }
.hl-cta-qr-img { width: 200px; height: 200px; object-fit: cover; background: #fff; border-radius: 8px; padding: 6px; box-sizing: border-box; display: block; }
.hl-article-cta-note { margin: 8px 0 0; font-size: 12px; opacity: 0.7; }

@media (min-width: 640px) {
  .hl-article-cta { flex-direction: row; align-items: center; gap: 32px; }
}

/* Online-contact button (L116) · used by CTA card + footer + section templates */
.hl-cta-online-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--wp--preset--color--accent, #2563EB);
  color: #FFFFFF;
  padding: 12px 24px;
  border-radius: 9999px;
  font-size: 15px;
  font-weight: 700;
  text-decoration: none;
  transition: opacity 0.15s ease;
}
.hl-cta-online-btn:hover { opacity: 0.88; }

/* ==========================================================================
   11. Breadcrumb · neutral
   ========================================================================== */

.hl-breadcrumb {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 14px;
  font-family: var(--wp--preset--font-family--inter, "Inter"), sans-serif;
  font-size: 14px;
  color: var(--wp--preset--color--body, #44474B);
}

.hl-breadcrumb a {
  color: var(--wp--preset--color--body, #44474B);
  text-decoration: none;
}

.hl-breadcrumb a:hover { color: var(--wp--preset--color--heading, #1A1C1E); }
.hl-breadcrumb .sep { font-size: 12px; opacity: 0.5; }
.hl-breadcrumb-current {
  color: var(--wp--preset--color--heading, #1A1C1E);
  font-weight: 600;
}

/* ==========================================================================
   12. Skip-to-content (a11y · L47 baseline-required)
   ========================================================================== */

.hl-skip-link {
  position: absolute;
  left: -9999px;
  top: 8px;
  z-index: 99999;
  background: var(--wp--preset--color--ink, #0F172A);
  color: #fff;
  padding: 12px 16px;
  text-decoration: none;
  font-size: 14px;
  border-radius: 4px;
}

.hl-skip-link:focus {
  left: 16px;
  outline: 2px solid var(--wp--preset--color--accent, #2563EB);
  outline-offset: 2px;
}

/* ==========================================================================
   13. Focus-visible (a11y · L47 baseline-required)
   ========================================================================== */

:focus-visible {
  outline: 2px solid var(--wp--preset--color--accent, #2563EB);
  outline-offset: 2px;
  border-radius: 2px;
}

/* ==========================================================================
   14. Single-post prev/next nav (neutral · projects may restyle .hl-post-nav)
   ========================================================================== */

.hl-post-nav {
  border-top: 1px solid var(--wp--preset--color--border, #E5E7EB);
}
.hl-post-nav .wp-block-post-navigation-link {
  max-width: 48%;
  font-size: 0.95rem;
}
.hl-post-nav .wp-block-post-navigation-link a { text-decoration: none; }
.hl-post-nav .wp-block-post-navigation-link a:hover { text-decoration: underline; }
