/*
 * Newstarsec bilingual site-wide CSS overrides — NSTAR-EPIC-009
 *
 * Enqueued in functions.php with filemtime() cache-busting (R20).
 * Covers both ZH and EN unless an override is scoped via html[lang^="en"].
 */

/* ============================================================
 * Footer — Global Office Network: uniform column height + phone-at-bottom
 * ============================================================
 * Issue: address lines wrap to 1 / 2 / 3 lines depending on city,
 * leaving phone numbers visually misaligned across the grid. Fix by
 * making each city cell a flex-column with the phone anchor pushed
 * to the bottom via `margin-top: auto`. Applies to ZH + EN — both
 * benefit from even baselines.
 */
.gb-element-bfe8b211 {
    align-items: stretch;
}
.gb-element-bfe8b211 > div {
    display: flex;
    flex-direction: column;
    height: 100%;
}
.gb-element-bfe8b211 > div > a[href^="tel:"] {
    margin-top: auto;
}
.gb-element-bfe8b211 > div > p.gb-text {
    /* Address paragraph — consistent line-height + break long address tokens */
    line-height: 1.5;
    overflow-wrap: break-word;
    word-break: normal;
}
.gb-element-bfe8b211 > div > h5.gb-text {
    /* City name — consistent margin-bottom so single-line titles match multi-line */
    margin-bottom: 0.5rem;
}

/* ============================================================
 * EN-scoped overrides — English text density adjustments
 * ============================================================ */
html[lang^="en"] .gb-element-bfe8b211 > div > p.gb-text {
    /* English street-address text is usually longer than ZH — tighten hyphenation */
    hyphens: auto;
    -webkit-hyphens: auto;
}

/* Footer link columns: keep lists left-aligned + consistent line-height */
html[lang^="en"] .gbp-footer ul {
    line-height: 1.6;
}

/* ============================================================
 * Top navigation — keep all 9 top-level items on a single line (ZH + EN)
 * ============================================================
 * After the 法律业务 / Legal dropdown was added 2026-05-22, both menus now
 * have 9 top-level items. With GP's default 20px L/R (or the prior R22
 * EN-only 12px override) the menu exceeds the available width inside
 * the 1140px header container and "Portal" wraps to a second row.
 *
 * Fix: tighten top-level padding to 8px L/R for both ZH + EN at >=769px
 * (mobile hamburger breakpoint untouched). Keep padding-right:0 on items
 * with submenu so the chevron icon stays visually flush — matches GP's
 * stock behaviour. Apply white-space:nowrap on both languages.
 *
 * Supersedes the EN-only R22 block formerly in generatepress_child/style.css
 * — that block is now a pointer comment, all logic lives here.
 */
@media (min-width: 769px) {
    #menu-primary > li > a,
    #menu-primary-en > li > a {
        padding-left: 8px;
        padding-right: 8px;
        white-space: nowrap;
    }
    #menu-primary > li.menu-item-has-children > a,
    #menu-primary-en > li.menu-item-has-children > a {
        padding-right: 0;
    }
}

/* Hero — widen text column on EN so English copy doesn't wrap cramped.
 * The hero inner .gb-element-b749a7a6 is a 2-col grid (text | empty/bg).
 * Default 1fr:1fr = 50/50 → shift to 1.5fr:1fr so text column goes from
 * ~50% to ~60% of container (≈20% wider). Grid collapses to block at
 * <=1024px so this only applies on desktop. */
html[lang^="en"] .gb-element-b749a7a6 {
    grid-template-columns: 1.5fr 1fr;
}

/* ============================================================
 * Employer-sponsored section — align tagline/headline rows across cards
 * ============================================================
 * Section .gb-element-11c0ef3b has 3 rows × 2 cards. Each card's inner
 * div holds tagline + headline + text. EN taglines vary 34–52 chars and
 * headlines vary 33–50 chars, so some wrap to 2 lines and some don't —
 * the headline/text starting row drifts across cards in a row.
 *
 * Reserve 2 line-heights on tagline + headline so every card's body text
 * starts on the same Y. ZH content is short (~9–17 chars), fits on 1 line,
 * and visually sits at the top of the reserved box — small vertical gap
 * on ZH but guaranteed row alignment across languages. */
.gb-element-11c0ef3b .gbp-section__inner .gbp-section__tagline,
.gb-element-11c0ef3b .gbp-section__inner .gbp-section__headline {
    min-height: 2.8em; /* fallback */
    min-height: 2lh;   /* precise: exactly 2 line-heights */
}

/* ============================================================
 * Mobile QA 2026-05-21 R2 — data tables: native responsive card transform
 * ============================================================
 * Strategy: at ≤640px, transform comparison tables into label/value cards
 * via the industry-standard `display: block` + `td::before { content: attr(data-label) }`
 * pattern. Server-side filter (mu-plugin newstarsec-responsive-tables.php) injects
 * `data-label="<th text>"` on every <td>, and tags the wrapper with class
 * `.nss-resp-table` so only successfully-labelled tables get cardised.
 *
 * Why not horizontal-scroll-with-min-width (R1 fix)? At 320px even 560px tables
 * still cram English labels into 1-2-word vertical stacks. Cards give each value
 * full row width — readable on any phone.
 *
 * Why not GenerateBlocks Container rewrite per page? Tables are baked into
 * post_content as raw HTML <table>/<tr>/<td> with per-page <style> blocks (54
 * distinct table classes across 45 pages). A GB rewrite would mean 45 manual
 * DB edits + maintaining two representations per page. This CSS pattern keeps
 * tables as a single source of truth.
 *
 * Why not a CSS-only approach without the data-label PHP filter? Because the
 * WP <th>→<td> link is positional, not semantic in HTML; without the data-label
 * attribute, mobile cards lose their column context ("$3,000/mo" becomes a
 * naked value with no "Tuition fee" label).
 *
 * Falls back to plain table for: tables without thead, tables with colspan
 * (filter leaves them as-is and does NOT tag them with .nss-resp-table, so the
 * card transform skips them and they render as scroll tables).
 */
@media (max-width: 640px) {
    /* Card transform: only applies to <table> tagged .nss-resp-table by the PHP filter.
     * Tagging the table itself (rather than its wrapper) means this works whether the
     * table is inside a `[name]-wrap` div, a GenerateBlocks `gb-element-XXX` container,
     * or has no wrapper at all. */
    .entry-content table.nss-resp-table,
    .entry-content table.nss-resp-table > thead,
    .entry-content table.nss-resp-table > tbody,
    .entry-content table.nss-resp-table > tbody > tr,
    .entry-content table.nss-resp-table > tbody > tr > td {
        display: block;
        width: 100%;
        box-sizing: border-box;
    }
    /* Reset table-level styles that would conflict with block layout */
    .entry-content table.nss-resp-table {
        border-collapse: separate;
        border-spacing: 0;
        border: 0;
        background: transparent;
        box-shadow: none;
    }
    /* Visually hide the original <thead> — labels now live on each cell via ::before */
    .entry-content table.nss-resp-table > thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        white-space: nowrap;
        margin: -1px;
        padding: 0;
        border: 0;
    }
    /* Each <tr> becomes a card */
    .entry-content table.nss-resp-table > tbody > tr {
        margin: 0 0 14px;
        padding: 16px 18px;
        background: #ffffff;
        border: 1px solid #e2e8f0;
        border-radius: 12px;
        box-shadow: 0 2px 6px rgba(15, 23, 42, 0.04);
    }
    /* Each cell becomes a label / value row */
    .entry-content table.nss-resp-table > tbody > tr > td {
        padding: 8px 0;
        border: 0;
        border-top: 1px solid #f1f5f9;
        text-align: left;
    }
    .entry-content table.nss-resp-table > tbody > tr > td:first-child {
        border-top: 0;
    }
    /* Label generated from the data-label attribute the PHP filter injected */
    .entry-content table.nss-resp-table > tbody > tr > td[data-label]::before {
        content: attr(data-label);
        display: block;
        font-size: 11px;
        font-weight: 700;
        letter-spacing: 0.05em;
        text-transform: uppercase;
        color: #64748b;
        margin-bottom: 4px;
    }
    /* First column in each row is the row's identity — render as the card title:
     * larger, bolder, navy accent, NO data-label prefix (because the first column
     * header is usually the row-identity column name like "学校" / "School" and
     * showing it above the value is redundant). */
    .entry-content table.nss-resp-table > tbody > tr > td.first-col,
    .entry-content table.nss-resp-table > tbody > tr > td:first-child {
        font-size: 1.0625rem;
        font-weight: 700;
        color: #1e3a5f;
        padding-bottom: 10px;
        margin-bottom: 4px;
    }
    .entry-content table.nss-resp-table > tbody > tr > td.first-col::before,
    .entry-content table.nss-resp-table > tbody > tr > td:first-child::before {
        display: none;
    }
    /* Strip per-page background colours / row striping that don't make sense on cards.
     * Per-page CSS often sets `.<class> tbody tr:nth-child(even) { background: ... }`
     * which would otherwise leak into the card layout. */
    .entry-content table.nss-resp-table > tbody > tr:nth-child(even),
    .entry-content table.nss-resp-table > tbody > tr:nth-child(odd) {
        background: #ffffff;
    }
}

/* ============================================================
 * Mobile QA 2026-05-21 R2 — opt-in horizontal scroll for true data tables
 * ============================================================
 * Reserved class `.nss-scroll-table` for any future table that legitimately
 * needs to stay tabular on mobile (large numeric matrices, where row/column
 * alignment is critical). Currently unused — all 45 affected pages benefit
 * from the card transform. Kept as a documented escape hatch.
 */
@media (max-width: 640px) {
    .entry-content .nss-scroll-table {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
    .entry-content .nss-scroll-table > table {
        min-width: 680px;
        width: max-content;
    }
    .entry-content .nss-scroll-table::before {
        content: "← Scroll horizontally to view full table →";
        display: block;
        margin: 0 0 8px;
        font-size: 12px;
        color: #64748b;
        font-weight: 600;
        text-align: center;
    }
    html[lang^="zh"] .entry-content .nss-scroll-table::before {
        content: "← 左右滑动查看完整表格 →";
    }
}

/* ============================================================
 * Mobile QA 2026-05-21 — nested-card padding on very narrow mobile
 * ============================================================
 * Codex's QA flagged 79 pages where cards-inside-cards (e.g. the
 * Working-Holiday phase cards inside a section card) leave only
 * ~134 px of text width at 320px. Outer cards use padding: 2rem
 * (32px); inner cards use padding: 1.75rem (28px). At 320px viewport
 * the combined eat-out is severe.
 *
 * Fix: under 360px, tighten any nested .gb-element (a GenerateBlocks
 * container that is itself inside another GB container) to 1rem
 * horizontal padding. Section-level containers are untouched.
 */
@media (max-width: 360px) {
    .entry-content .gb-element .gb-element {
        padding-left: 1rem !important;
        padding-right: 1rem !important;
    }
}

/* ============================================================
 * Mobile QA 2026-05-21 — Google Reviews: hide rating-only slides
 * ============================================================
 * Codex's QA flagged the homepage Google Reviews carousel rendering
 * a blank card body on mobile. Cause: the first review in the feed
 * (Sydney Translation, 5★) has no review text — Google allows
 * stars-only ratings — so widget-google-reviews renders an empty
 * .wp-google-feedback container. The card looks broken even though
 * the plugin is behaving correctly.
 *
 * Fix: hide carousel slides whose feedback container is empty. The
 * carousel rebuilds the visible slide count from the rendered DOM,
 * so display:none collapses the slot and the user only sees reviews
 * that have actual text content.
 */
.rpi-slide.grw-review:has(.wp-google-feedback:empty) {
    display: none !important;
}

/* ============================================================
 * Footer city strip (2026-05-24, R3)
 * ============================================================
 * Thin horizontal row of city names at the very bottom of the
 * footer, separated by middle-dot characters. Plain-text styling
 * — overrides GP's global `a:hover { color: var(--accent-2) }`
 * (which would otherwise flash the city names orange #E48216).
 *
 * Markup:
 *   <div class="nss-footer-cities">
 *     <a href="/offices/#sydney">悉尼</a>
 *     <span class="sep">·</span>
 *     <a href="/offices/#melbourne">墨尔本</a>
 *     ...
 *   </div>
 */
.nss-footer-cities {
    display: flex;
    flex-wrap: nowrap;
    justify-content: center;
    align-items: center;
    column-gap: 1.4rem;
    padding: 1.5rem 1rem 1rem;
    max-width: var(--gb-container-width);
    margin: 0 auto;
    font-size: 0.85rem;
    line-height: 1.4;
    color: rgba(255, 255, 255, 0.45);
    white-space: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}
.nss-footer-cities::-webkit-scrollbar {
    display: none;
}
.nss-footer-cities a,
.nss-footer-cities a:link,
.nss-footer-cities a:visited {
    color: rgba(255, 255, 255, 0.55) !important;
    text-decoration: none !important;
    font-weight: 400;
    transition: color 0.15s ease;
    flex: 0 0 auto;
}
.nss-footer-cities a:hover,
.nss-footer-cities a:focus,
.nss-footer-cities a:active {
    color: rgba(255, 255, 255, 0.9) !important;
    text-decoration: none !important;
}
.nss-footer-cities .sep {
    color: rgba(255, 255, 255, 0.2);
    user-select: none;
    -webkit-user-select: none;
    flex: 0 0 auto;
}
/* (Old 640px override removed — superseded by R5d 767px grid layout below) */

/* ============================================================
 * Footer brand cell — logo proportions + column alignment (2026-05-24, R5)
 * ============================================================
 * Companion to the GB markup patch (05_patch_footer_r5.php) that:
 *   - Stripped `align:full` + `alignfull` class from logo wp:image
 *   - Bumped H4 line-height 0.5 → 1.2 on 快速导航 / 常见服务
 *   - Set 517623ed grid to 2fr 1fr 1fr (brand col wider)
 *
 * What this CSS does:
 *   - Caps logo at 44px tall (matches H4 visual weight in adjacent cols)
 *   - Adds breathing room below logo before description text
 *   - Constrains description width so it doesn't crowd the nav column
 *   - Resets figure margins (default wp-block-image margin yanks layout)
 */
.gb-element-55ebd29d .wp-block-image {
    margin: 0 0 1.25rem;
}
.gb-element-55ebd29d .wp-block-image img {
    max-height: 112px;
    width: auto;
    height: auto;
    display: block;
}
.gb-element-55ebd29d p {
    max-width: 320px;
    line-height: 1.7;
    margin: 0;
}
@media (max-width: 767px) {
    .gb-element-55ebd29d {
        margin-bottom: 1.5rem;
    }
    .gb-element-55ebd29d p {
        max-width: 100%;
    }
}

/* ============================================================
 * Footer — mobile layout polish (2026-05-24, R5d)
 * ============================================================
 * On screens ≤ 767px:
 *   - Logo + description centered (was left-aligned)
 *   - 快速导航 + 常见服务 columns centered (headers + links)
 *   - City strip → 5-column grid (2 rows of 5), no horizontal scroll,
 *     dot separators hidden (cleaner with grid spacing)
 *   - Copyright + social icons stack vertically, both centered
 *
 * Selectors prefixed with .site-footer to outrank inline GB block CSS
 * (which loads via <style> AFTER child theme link, same specificity
 * (0,1,0) → inline would win at equal specificity. .site-footer ancestor
 * bumps mine to (0,2,0) so the cascade always picks ours.)
 */
@media (max-width: 767px) {
    .site-footer .gb-element-55ebd29d {
        text-align: center;
    }
    .site-footer .gb-element-55ebd29d .wp-block-image img,
    .site-footer .gb-element-55ebd29d p {
        margin-left: auto;
        margin-right: auto;
    }
    .site-footer .gb-element-d7f00cf0,
    .site-footer .gb-element-07477ddf {
        text-align: center;
    }
    .site-footer .nss-footer-cities {
        display: grid;
        grid-template-columns: repeat(5, 1fr);
        justify-content: center;
        gap: 0.55rem 0.4rem;
        overflow-x: visible;
        white-space: normal;
        padding: 1.25rem 0.5rem 1rem;
        font-size: 0.78rem;
    }
    .site-footer .nss-footer-cities a {
        flex: initial;
        text-align: center;
    }
    .site-footer .nss-footer-cities .sep {
        display: none;
    }
    .site-footer .gb-element-2fbf9b63 {
        flex-direction: column;
        align-items: center;
        text-align: center;
        row-gap: 1rem;
    }
    /* Uniform horizontal padding on the outer container so brand-cell text,
       headers, city strip, and copyright all share consistent inset on mobile
       (prevents the description text from touching the viewport edge). */
    .site-footer .gb-element-87e4d6f9 {
        padding-left: 1.25rem;
        padding-right: 1.25rem;
    }
}


/* ════════════════════════════════════════════════════════════════
 * Migrated from Customizer Additional CSS — 2026-06-11 (tech-review L7)
 * Reason: WP 7.0 injects Customizer CSS into the block editor canvas,
 * blanking pages that use .scroll-fade-in opacity rules. Serving these
 * rules from the child theme keeps them frontend-only, which also
 * retired the aureole-fix-editor-customizer-css mu-plugin.
 * NOTE: future edits to these rules happen HERE (via SSH), not in the
 * Customizer. Do not re-add animation CSS to Customizer Additional CSS.
 * ════════════════════════════════════════════════════════════════ */

/* === FADE IN ON LOAD (for elements above the fold) === */
@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(30px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.fade-in-up {
  animation: fadeInUp 0.8s ease-out both;
}

/* Stagger delays for sequential elements */
.fade-in-up.delay-1 { animation-delay: 0.1s; }
.fade-in-up.delay-2 { animation-delay: 0.2s; }
.fade-in-up.delay-3 { animation-delay: 0.3s; }
.fade-in-up.delay-4 { animation-delay: 0.4s; }
.fade-in-up.delay-5 { animation-delay: 0.5s; }

/* Variations */
.fade-in {
  animation: fadeIn 0.8s ease-out both;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes fadeInLeft {
  from {
    opacity: 0;
    transform: translateX(-30px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

.fade-in-left {
  animation: fadeInLeft 0.8s ease-out both;
}

@keyframes fadeInRight {
  from {
    opacity: 0;
    transform: translateX(30px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

.fade-in-right {
  animation: fadeInRight 0.8s ease-out both;
}

/* Respect user preferences */
@media (prefers-reduced-motion: reduce) {
  .fade-in-up,
  .fade-in,
  .fade-in-left,
  .fade-in-right {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
}

/* Hidden state before scrolling into view */
.scroll-fade-in {
  opacity: 0;
  transform: translateY(30px);
  transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}

.scroll-fade-in-left {
  opacity: 0;
  transform: translateX(-40px);
  transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}

.scroll-fade-in-right {
  opacity: 0;
  transform: translateX(40px);
  transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}

/* Visible state */
.scroll-fade-in.is-visible,
.scroll-fade-in-left.is-visible,
.scroll-fade-in-right.is-visible {
  opacity: 1;
  transform: translate(0);
}

/* Stagger children inside a container */
.stagger-children.is-visible > * {
  opacity: 1;
  transform: translateY(0);
}

.stagger-children > * {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.5s ease-out, transform 0.5s ease-out;
}

.stagger-children.is-visible > *:nth-child(1) { transition-delay: 0.1s; }
.stagger-children.is-visible > *:nth-child(2) { transition-delay: 0.2s; }
.stagger-children.is-visible > *:nth-child(3) { transition-delay: 0.3s; }
.stagger-children.is-visible > *:nth-child(4) { transition-delay: 0.4s; }
.stagger-children.is-visible > *:nth-child(5) { transition-delay: 0.5s; }
.stagger-children.is-visible > *:nth-child(6) { transition-delay: 0.6s; }

/* Respect user preferences */
@media (prefers-reduced-motion: reduce) {
  .scroll-fade-in,
  .scroll-fade-in-left,
  .scroll-fade-in-right,
  .stagger-children > * {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}

/* Home Page Post card title - max 2 lines */
.title-line-clamp-2 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Post card excerpt - max 2 lines */
.content-line-clamp-2 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* The card needs to be a positioning context */
.gbp-card {
    position: relative;
}
/* 1. Make the main link cover the whole container */
.linked-container {
    position: relative;
}

.linked-container a:first-of-type::before {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1; /* The "base" clickable layer */
}

/* 2. Bring the DIFFERENT secondary links to the front */
.linked-container a:not(:first-of-type), 
.linked-container button,
.linked-container .secondary-link-class a {
    position: relative;
    z-index: 10; /* Higher than the container link */
}



/* Round-3 nav padding fix — keep menu on one line */
@media (min-width: 769px) {
    .main-navigation .main-nav ul li a {
        padding-left: 12px;
        padding-right: 12px;
    }
    .main-navigation .main-nav ul ul li a {
        padding-left: 20px;
        padding-right: 20px;
    }
}
/* end nav-padding-fix */

/* === Submenu dropdown shadow + depth (ref: NSLegal overlay-panel) — 2026-05-28 [submenu-shadow s100] === */
.main-navigation .main-nav ul ul,
.main-navigation ul.sub-menu {
    box-shadow: 0 2px 4px rgba(0,0,0,0.06), 0 10px 20px rgba(15,35,66,0.13);
}
/* === end submenu-shadow === */
