/* Alchemys — Home ("Editorial")
 *
 * Page-scoped design layer for web/index.html ONLY. Nothing else links this
 * sheet, so every :root token and every element override in here is confined
 * to the root page — the /<app>/info/ pages keep landing.css untouched.
 *
 * LOAD ORDER — must come AFTER landing.css:
 *
 *   tokens.css → shared.css → md3.css → dropdown.css → app-shell.css
 *   → landing.css → home.css   <- last
 *
 * It inherits the Paper token names (--bg, --text, --accent, --ease-apple…)
 * so the shared components that consume them — the custom select, the app
 * launcher flyout, the notification panel, modals — stay coherent. It then
 * re-points the neutral ramp warmer and replaces the card-wall composition
 * with an editorial one: a real 12-column grid, hairlines instead of shadows,
 * numerals as design elements, and one accent used sparingly.
 *
 * Class prefix is `hm-` so nothing here collides with landing.css. The one
 * exception is the generated FAQ block, which is emitted by
 * packages/contracts/scripts/seo-canonical.mjs with .card / .display / Tailwind
 * utility classes and must not be hand-edited — it is restyled by #faq
 * descendant selectors at the bottom of this file instead.
 */

/* ==========================================================================
   1. Tokens — warm paper, editorial scale
   ========================================================================== */

:root {
    /* Neutral ramp. Warmer than Paper's blue-grey so the page reads as stock,
       not as a screen. The step from --hm-paper to --hm-raise is deliberately
       small: separation comes from rules, not from stacked surfaces. */
    --hm-paper: #f7f6f3;
    --hm-paper-2: #efeee9;
    --hm-raise: #ffffff;
    --hm-ink: #16161a;
    --hm-ink-2: #56565e;
    /* The lightest step still used for TEXT, not just numerals: the section
       eyebrows, the four stat labels, the rail hint and the four footer
       heads are all 11px. #86868b measured 3.35:1 on --hm-paper and 3.12:1 on
       the footer's --hm-paper-2 — below the 4.5:1 AA floor for body text,
       and the large-text exemption is not available at 11px/560.
       #6b6b73 measures 4.89:1 on paper, 5.28:1 on --hm-raise (cards) and
       4.55:1 on --hm-paper-2 (footer) — the paper-2 case is the binding one. */
    --hm-ink-3: #6b6b73;

    /* Hairlines. --hm-rule is the workhorse; --hm-rule-2 is for a division
       the eye should actually stop at (section boundaries). */
    --hm-rule: rgba(22, 22, 26, 0.12);
    --hm-rule-2: rgba(22, 22, 26, 0.22);

    /* One accent. Apple link blue, same as Paper, so CTAs match the suite. */
    --hm-accent: #0071e3;
    --hm-accent-soft: rgba(0, 113, 227, 0.08);
    --hm-on-accent: #ffffff;

    /* Grid */
    --hm-max: 1240px;
    --hm-gutter: clamp(20px, 5vw, 56px);

    /* Type — tracking is size-specific (never one value for all sizes):
       negative as it grows, ~0 at body, positive for small caps. */
    /* Capped so the longest headline line ("The AI workspace") still fits the
       hero's 7-of-12 column on one line — above ~4.6rem it breaks after "The
       AI", which reads as a mistake rather than a line break. */
    --hm-t-display: clamp(2.6rem, 5.6vw, 4.6rem);
    --hm-t-h2: clamp(2rem, 4.6vw, 3.4rem);
    --hm-t-h3: clamp(1.25rem, 2.2vw, 1.6rem);
    --hm-t-lede: clamp(1.0625rem, 1.3vw, 1.1875rem);
    --hm-t-body: 0.9375rem;
    --hm-t-small: 0.8125rem;
    --hm-t-micro: 0.6875rem;

    /* Motion — the one curve, plus a gentle overshoot reserved for anything
       the user actually threw. */
    --hm-ease: cubic-bezier(0.32, 0.72, 0, 1);
    --hm-quick: 140ms;
    --hm-lift: 225ms;
    --hm-reveal: 435ms;
}

/* Dark ramp. Lifted off near-black (was #08080a paper / #17171b raise): at that
   depth the page read as a void, the 9px step between paper and card was below
   the threshold most screens resolve, and the root page sat visibly darker than
   the app it leads into. Anchored instead on Studio's shell (shared.css
   --bg-color #131314 / --card-bg #1e1f20) so crossing from here into /studio/
   is not a brightness jump, with the step between paper and raise widened to
   ~14 points so cards separate on their own. */
html.dark {
    --hm-paper: #141417;
    --hm-paper-2: #1b1b1f;
    --hm-raise: #212126;
    --hm-ink: #f4f4f2;
    --hm-ink-2: #a8a8b0;
    /* Same 11px-label problem as the light step, one ramp over: #83838d
       measured 4.27:1 on --hm-raise, which is where .hm-card-idx and the
       tile index numerals sit. #8c8c96 measures 5.52:1 on --hm-paper, 4.81:1
       on --hm-raise and 5.16:1 on --hm-paper-2 (footer). */
    --hm-ink-3: #8c8c96;
    --hm-rule: rgba(244, 244, 242, 0.13);
    --hm-rule-2: rgba(244, 244, 242, 0.24);
    --hm-accent: #2997ff;
    --hm-accent-soft: rgba(41, 151, 255, 0.14);
    /* The light :root value of --hm-on-accent is #ffffff, which reads 3.02:1
       against this accent — a fail for the 15px/560 primary CTA. Dark is what
       a visitor on a dark OS gets here for free: index.html adds .dark from
       prefers-color-scheme before first paint, so the un-redeclared :root
       value was live for the entire dark scheme. #08243f on #2997ff measures
       5.22:1. White stays correct in the light scheme: 4.70:1 on #0071e3. */
    --hm-on-accent: #08243f;
}

/* The MD3 bridge, re-pointed at THIS page's warm ramp.
 *
 * landing.css bridges these too, but at the Paper (cool) values. This block
 * overrides it for the root page only, so the shared components it mounts —
 * the launcher flyout, the notification panel, the dashboard feed, modals and
 * the custom select — sit on the same warm neutral as everything around them.
 *
 * The selector deliberately mirrors landing.css's: shared.css declares its
 * light Material You set on `html:not(.dark):not(.dark-mode)` (0,2,1), so a
 * plain `:root` here would lose to it regardless of load order.
 */
html:not(.dark):not(.dark-mode),
html.dark,
html.dark-mode {
    --md-surface-container-lowest: var(--hm-paper);
    --md-surface-container-low: var(--hm-raise);
    --md-surface-container: var(--hm-paper-2);
    --md-surface-container-high: var(--hm-paper-2);
    --md-surface-container-highest: var(--hm-paper-2);
    --md-surface: var(--hm-paper);
    --md-on-surface: var(--hm-ink);
    --md-on-surface-variant: var(--hm-ink-2);
    --md-outline: var(--hm-rule-2);
    --md-outline-variant: var(--hm-rule);
    --md-primary: var(--hm-accent);
    --md-on-primary: var(--hm-on-accent);
    --md-primary-container: var(--hm-accent-soft);
    --md-on-primary-container: var(--hm-ink);
}

/* Re-point the Paper tokens the shared components read, so the launcher
   flyout / notification panel / modals / custom select inherit this page's
   ramp instead of sitting on landing.css's cooler one. */
:root, html.dark {
    --bg: var(--hm-paper);
    --bg-soft: var(--hm-paper-2);
    --surface: var(--hm-raise);
    --surface-2: var(--hm-paper-2);
    --border: var(--hm-rule);
    --border-strong: var(--hm-rule-2);
    --text: var(--hm-ink);
    --text-2: var(--hm-ink-2);
    --text-3: var(--hm-ink-3);
    --accent: var(--hm-accent);
    --accent-soft: var(--hm-accent-soft);
}

/* ==========================================================================
   2. Base
   ========================================================================== */

/* Preflight replacement. Every other page in the suite gets these three
   resets from Tailwind's Preflight, which ships inside js/shared/tailwind-browser.js.
   This page dropped that runtime (see §18) and nothing in the rest of the
   chain — tokens/shared/md3/dropdown/app-shell/landing — declares them, so
   they have to be restated here or the whole layer is authored against a
   box model it does not have:
     - border-box: .hm-wrap is `width:100%` PLUS `padding-inline: var(--hm-gutter)`.
       Under content-box that is 100% + 2×gutter, so every wrapper on the page
       ran ~40-112px wider than the viewport and the document scrolled
       sideways at every width.
     - body margin: the UA's 8px gutter was showing on both edges and pushing
       the sticky nav out of alignment with the content it sits over.
     - link decoration: without it every card, tile, nav item, footer entry and
       CTA rendered with a UA underline. */
*, *::before, *::after { box-sizing: border-box; }

body {
    margin: 0;
    background: var(--hm-paper);
    color: var(--hm-ink);
    font-size: 16px;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
}

/* Links carry their meaning through position, colour and an arrow, never
   through a rule under the text. The components that *are* body-copy links
   opt back in on hover below. */
a { color: inherit; text-decoration: none; }

/* The one exception: a bare anchor inside running prose (the footer contact
   address) has no card, arrow or accent of its own, so it needs to look like
   a link. */
.hm-foot-lead a {
    color: var(--hm-accent);
    text-decoration-color: transparent;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
    transition: text-decoration-color var(--hm-quick) var(--hm-ease);
}

.hm-foot-lead a:hover { text-decoration: underline; text-decoration-color: currentColor; }

/* This page toggles visibility with el.hidden. The UA stylesheet's
   `[hidden] { display: none }` is beaten by ANY author display rule, so
   .hm-btn (inline-flex) and .hm-mobilebar (flex) would ignore it outright —
   leaving the Launch button and the floating CTA on screen for signed-in
   users looking at their dashboard. */
[hidden] { display: none !important; }

/* Tabular figures everywhere a number is used as a design element — section
   numerals, the figure row, rail indices. Proportional digits make a column
   of numbers look broken. */
.hm-num, .hm-fig-value, .hm-card-idx, .hm-step-num {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* --- Grid ---------------------------------------------------------------- */

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

.hm-grid {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: clamp(16px, 2.5vw, 32px);
}

/* --- Section rhythm ------------------------------------------------------
   Deliberately uneven. A page where every section has identical padding reads
   as a template; the hero gets the most air, the spec sections the least. */

.hm-sec { padding-block: clamp(72px, 11vw, 140px); }
.hm-sec--tight { padding-block: clamp(56px, 7vw, 88px); }
.hm-sec--ruled { border-top: 1px solid var(--hm-rule); }

.hm-sec-head {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: clamp(16px, 2.5vw, 32px);
    row-gap: 20px;
    align-items: end;
    margin-bottom: clamp(40px, 6vw, 72px);
}

.hm-sec-title { grid-column: 1 / -1; }
.hm-sec-aside { grid-column: 1 / -1; }

@media (min-width: 900px) {
    .hm-sec-title { grid-column: 1 / 8; }
    .hm-sec-aside { grid-column: 9 / -1; padding-bottom: 6px; }
}

/* --- Typography ---------------------------------------------------------- */

.hm-kicker {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    font-size: var(--hm-t-micro);
    font-weight: 600;
    letter-spacing: 0.1em;      /* positive tracking — small text needs air */
    text-transform: uppercase;
    color: var(--hm-ink-3);
}

.hm-kicker::before {
    content: "";
    width: 22px;
    height: 1px;
    background: var(--hm-rule-2);
}

.hm-num {
    font-size: var(--hm-t-micro);
    font-weight: 600;
    letter-spacing: 0.1em;
    color: var(--hm-ink-3);
}

.hm-display {
    font-size: var(--hm-t-display);
    font-weight: 680;
    line-height: 0.94;          /* tight leading — large text only */
    letter-spacing: -0.038em;   /* negative tracking, strongest at the top end */
    text-wrap: balance;
}

.hm-h2 {
    font-size: var(--hm-t-h2);
    font-weight: 660;
    line-height: 1.04;
    letter-spacing: -0.028em;
    text-wrap: balance;
}

/* Section headings that are a two-line lockup of two locale strings. Left
   inline they reflow into each other and break mid-phrase ("170+ models. One /
   prompt surface."). Not applied to .hm-h2 generally: the dashboard heading is
   one sentence split across two keys and must stay inline. */
.hm-h2--stack > span { display: block; }

.hm-h3 {
    font-size: var(--hm-t-h3);
    font-weight: 620;
    line-height: 1.18;
    letter-spacing: -0.018em;
}

.hm-lede {
    font-size: var(--hm-t-lede);
    line-height: 1.5;
    letter-spacing: -0.006em;
    color: var(--hm-ink-2);
    text-wrap: pretty;
}

.hm-body {
    font-size: var(--hm-t-body);
    line-height: 1.6;
    color: var(--hm-ink-2);
    text-wrap: pretty;
}

.hm-accent { color: var(--hm-accent); }
.hm-ink-2 { color: var(--hm-ink-2); }
.hm-ink-3 { color: var(--hm-ink-3); }

/* CJK does not want the Latin tracking. Cantonese and Simplified headlines
   read as cramped at -0.038em, and their ascenders want more leading. */
html[lang^="zh"] .hm-display { letter-spacing: -0.012em; line-height: 1.08; }
html[lang^="zh"] .hm-h2 { letter-spacing: -0.008em; line-height: 1.16; }
html[lang^="zh"] .hm-h3 { letter-spacing: -0.004em; }
html[lang^="zh"] .hm-lede,
html[lang^="zh"] .hm-body { line-height: 1.72; letter-spacing: 0; }

/* ==========================================================================
   3. Navigation — translucent, no hard divider
   ========================================================================== */

.hm-nav {
    position: sticky;
    top: 0;
    z-index: 50;
    background: color-mix(in srgb, var(--hm-paper) 72%, transparent);
    backdrop-filter: saturate(180%) blur(20px);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
}

.hm-nav-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    height: 58px;
}

/* Scroll edge effect, not a 1px border: the separation fades in only once
   content has actually travelled under the bar. */
.hm-nav::after {
    content: "";
    position: absolute;
    inset-inline: 0;
    bottom: -1px;
    height: 1px;
    background: var(--hm-rule);
    opacity: 0;
    transition: opacity var(--hm-quick) var(--hm-ease);
}

.hm-nav.is-scrolled::after { opacity: 1; }

.hm-brand {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    /* The brand wordmark is runtime-swapped (brand.js), so its length is not known at
       authoring time. Without a shrinkable, clip-able brand the actions row gets
       pushed past the viewport on a narrow phone, which scrolls the sticky header
       horizontally - the one thing the header must never do. */
    min-width: 0;
    flex: 0 1 auto;
    background: none;
    border: 0;
    padding: 6px 8px 6px 0;
    color: var(--hm-ink);
    cursor: pointer;
    border-radius: 10px;
    transition: opacity var(--hm-quick) var(--hm-ease);
}

.hm-brand:hover { opacity: 0.6; }
.hm-brand:active { opacity: 0.45; }
.hm-brand:focus-visible { outline: 2px solid var(--hm-accent); outline-offset: 3px; }

.hm-brand-name {
    font-size: 16px;
    font-weight: 640;
    letter-spacing: -0.02em;
    line-height: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.hm-brand-chev {
    font-size: 18px;
    opacity: 0.45;
    transition: transform var(--hm-quick) var(--hm-ease);
}

.hm-brand[aria-expanded="true"] .hm-brand-chev { transform: rotate(180deg); }

.hm-nav-actions { display: flex; align-items: center; gap: 4px; flex: 0 0 auto; }

.hm-nav-links {
    display: none;
    align-items: center;
    gap: 20px;
    margin-right: 8px;
}

@media (min-width: 640px) { .hm-nav-links { display: flex; } }

.hm-navlink {
    font-size: var(--hm-t-small);
    font-weight: 480;
    color: var(--hm-ink-2);
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    transition: color var(--hm-quick) var(--hm-ease);
}

.hm-navlink:hover { color: var(--hm-ink); }
.hm-navlink--danger:hover { color: #e0384b; }

.hm-iconbtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border: 0;
    border-radius: 999px;
    background: none;
    color: var(--hm-ink-2);
    cursor: pointer;
    position: relative;
    transition: background var(--hm-quick) var(--hm-ease),
                color var(--hm-quick) var(--hm-ease),
                transform var(--hm-quick) var(--hm-ease);
}

.hm-iconbtn:hover { background: var(--hm-paper-2); color: var(--hm-ink); }
.hm-iconbtn:active { transform: scale(0.92); }
.hm-iconbtn .material-symbols-outlined { font-size: 19px; }

/* On phones the sticky bottom bar already carries the primary CTA, so the nav
   copy is redundant and it is what pushes the row past the viewport. */
@media (max-width: 560px) {
    #nav-launch-btn { display: none; }
    .hm-nav-actions { gap: 2px; }
}

@media (max-width: 380px) {
    .hm-brand-chev { display: none; }
}

/* The language select is a real <select data-custom-select>, restyled by
   dropdown.css — this only reshapes the trigger to match the icon buttons. */
#lang-select.styled,
.hm-nav-actions .custom-select-trigger {
    min-height: 36px;
    border-radius: 999px;
    font-size: var(--hm-t-micro);
    letter-spacing: 0.04em;
    color: var(--hm-ink-2);
}

/* ==========================================================================
   4. Buttons
   ========================================================================== */

.hm-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 46px;
    padding: 0 22px;
    border: 1px solid transparent;
    border-radius: 999px;
    font-size: var(--hm-t-body);
    font-weight: 560;
    letter-spacing: -0.01em;
    cursor: pointer;
    white-space: nowrap;
    /* Press feedback is instant and lives on pointer-down, not on click. */
    transition: transform 75ms var(--hm-ease),
                background var(--hm-quick) var(--hm-ease),
                border-color var(--hm-quick) var(--hm-ease),
                color var(--hm-quick) var(--hm-ease);
}

.hm-btn:active { transform: scale(0.965); }
.hm-btn:focus-visible { outline: 2px solid var(--hm-accent); outline-offset: 3px; }

.hm-btn--primary {
    background: var(--hm-accent);
    color: var(--hm-on-accent);
}

.hm-btn--primary:hover { background: color-mix(in srgb, var(--hm-accent) 88%, #000); }

/* In dark the button carries DARK text on the accent, so the generic
   darken-on-hover above works against it: 88% #2997ff + 12% black lands on
   #2485e0, which drops #08243f to 4.13:1 — under AA for the same 15px label.
   Lighten instead, so the hover deepens the contrast the same way the light
   scheme does. #08243f on the resulting #43a3ff measures 5.94:1. */
html.dark .hm-btn--primary:hover { background: color-mix(in srgb, var(--hm-accent) 88%, #fff); }

.hm-btn--quiet {
    background: transparent;
    border-color: var(--hm-rule-2);
    color: var(--hm-ink);
}

.hm-btn--quiet:hover { background: var(--hm-paper-2); }

.hm-btn--sm { min-height: 36px; padding: 0 16px; font-size: var(--hm-t-small); }

.hm-arrowlink {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: var(--hm-t-body);
    font-weight: 520;
    color: var(--hm-accent);
}

.hm-arrowlink svg { transition: transform var(--hm-quick) var(--hm-ease); }
.hm-arrowlink:hover svg { transform: translateX(3px); }

/* ==========================================================================
   5. Hero
   ========================================================================== */

/* Bottom padding is small because the figure row already sits on a rule and
   the next section brings its own leading air. */
.hm-hero { padding-block: clamp(48px, 7vw, 88px) clamp(20px, 2.5vw, 32px); }

.hm-hero-grid { row-gap: clamp(48px, 7vw, 72px); align-items: start; }

.hm-hero-copy { grid-column: 1 / -1; }
.hm-hero-side { grid-column: 1 / -1; }

@media (min-width: 980px) {
    .hm-hero-copy { grid-column: 1 / 8; }
    .hm-hero-side { grid-column: 8 / -1; padding-top: 10px; }
}

.hm-hero-display { margin-top: 26px; }

/* Each locale line is its own line. Left inline, the spans reflow into each
   other and the headline breaks wherever the column happens to end. */
.hm-hero-display > span { display: block; }

/* The third line is the whole positioning — give it the accent. */
.hm-hero-display .hm-hero-accent { color: var(--hm-accent); }

.hm-hero-lede { margin-top: 26px; max-width: 33em; }

.hm-hero-actions {
    margin-top: 34px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
}

.hm-hero-note {
    margin-top: 18px;
    font-size: var(--hm-t-small);
    color: var(--hm-ink-3);
}

/* --- Router card ---------------------------------------------------------
   The hero's one piece of imagery, and it is the product's actual argument:
   one prompt surface fanning out to every model, settled by one balance. */

.hm-router {
    background: var(--hm-raise);
    border: 1px solid var(--hm-rule);
    border-radius: 20px;
    padding: 22px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03), 0 16px 40px rgba(0, 0, 0, 0.06);
}

html.dark .hm-router {
    box-shadow: none;
    background: var(--hm-raise);
}

.hm-router-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--hm-rule);
}

.hm-router-prompt {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: var(--hm-t-small);
    color: var(--hm-ink-2);
    min-width: 0;
}

.hm-router-caret {
    width: 2px;
    height: 15px;
    background: var(--hm-accent);
    border-radius: 1px;
    flex: none;
}

.hm-router-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
    padding-block: 18px;
}

.hm-chip {
    display: inline-flex;
    align-items: center;
    padding: 5px 11px;
    border: 1px solid var(--hm-rule);
    border-radius: 999px;
    font-size: var(--hm-t-micro);
    font-weight: 520;
    letter-spacing: 0.01em;
    color: var(--hm-ink-2);
    background: var(--hm-paper);
    transition: border-color var(--hm-quick) var(--hm-ease),
                color var(--hm-quick) var(--hm-ease),
                background var(--hm-quick) var(--hm-ease);
}

/* One chip is lit to show the router landed somewhere. Which one is lit is
   swapped by home.js on an interval slow enough to read, and never at all
   under reduced motion. */
.hm-chip.is-routed {
    border-color: var(--hm-accent);
    background: var(--hm-accent-soft);
    color: var(--hm-accent);
}

.hm-router-foot {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding-top: 16px;
    border-top: 1px solid var(--hm-rule);
    font-size: var(--hm-t-micro);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--hm-ink-3);
}

.hm-router-balance { color: var(--hm-ink); font-weight: 600; letter-spacing: 0.02em; }
/* The unit words are the point of the pair — "194 / 48" alone told a new visitor
   nothing — but they stay quiet so the counts still lead the line. */
.hm-router-unit { color: var(--hm-ink-3); font-weight: 500; }
.hm-router-sep { color: var(--hm-ink-3); font-weight: 500; margin: 0 5px; }

/* --- Figure row ----------------------------------------------------------
   Replaces the three-stat block. A single ruled row of numbers reads as a
   masthead; three bordered boxes read as a template. */

.hm-figures {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    border-top: 1px solid var(--hm-rule-2);
}

@media (min-width: 720px) { .hm-figures { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.hm-fig {
    padding: 22px 0 4px;
    border-right: 1px solid var(--hm-rule);
    padding-right: 16px;
}

.hm-fig:last-child { border-right: 0; }

@media (max-width: 719px) {
    .hm-fig:nth-child(2n) { border-right: 0; }
    .hm-fig:nth-child(n + 3) { border-top: 1px solid var(--hm-rule); }
}

.hm-fig-value {
    font-size: clamp(1.75rem, 3.4vw, 2.5rem);
    font-weight: 660;
    letter-spacing: -0.03em;
    line-height: 1.05;
}

/* A word unit only ("tokens"). A "+" belongs at full size inside the value —
   set at 0.5em it reads as a footnote marker rather than part of the number. */
.hm-fig-unit {
    font-size: 0.42em;
    font-weight: 520;
    letter-spacing: 0;
    color: var(--hm-ink-3);
    margin-left: 0.45em;
}

.hm-fig-label {
    margin-top: 7px;
    font-size: var(--hm-t-micro);
    font-weight: 560;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--hm-ink-3);
}

/* ==========================================================================
   6. App rail — drag, flick, rubber-band, spring snap
   ========================================================================== */

.hm-rail-sec { padding-block: clamp(56px, 8vw, 96px); }

.hm-rail-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 24px;
    margin-bottom: 26px;
}

.hm-rail-hint {
    display: none;
    align-items: center;
    gap: 8px;
    font-size: var(--hm-t-micro);
    font-weight: 560;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--hm-ink-3);
    white-space: nowrap;
}

@media (min-width: 720px) { .hm-rail-hint { display: inline-flex; } }

/* The viewport bleeds to the right edge so the next card is always half-cut —
   the clearest possible signal that the row continues. */
.hm-rail {
    position: relative;
    margin-right: calc(var(--hm-gutter) * -1);
    /* Without JS this is a plain scroller and everything still works. */
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    -ms-overflow-style: none;
    cursor: grab;
}

.hm-rail::-webkit-scrollbar { display: none; }
.hm-rail.is-dragging { cursor: grabbing; }

/* Once home.js takes over, the native scroller is retired and the track is
   driven by transform — the only way to get velocity handoff and a spring. */
.hm-rail.is-enhanced { overflow-x: hidden; touch-action: pan-y; }

.hm-rail-track {
    display: flex;
    gap: 14px;
    padding-right: var(--hm-gutter);
    will-change: transform;
}

.hm-rail.is-enhanced .hm-rail-track { transform: translate3d(0, 0, 0); }

.hm-card {
    flex: none;
    width: clamp(230px, 68vw, 288px);
    display: flex;
    flex-direction: column;
    min-height: 246px;
    padding: 20px;
    border: 1px solid var(--hm-rule);
    border-radius: 18px;
    background: var(--hm-raise);
    color: inherit;
    /* Dragging a rail of links must not start a native link drag. */
    -webkit-user-drag: none;
    user-select: none;
    transition: border-color var(--hm-lift) var(--hm-ease),
                transform var(--hm-lift) var(--hm-ease);
}

@media (min-width: 720px) { .hm-card { width: 288px; } }

.hm-rail:not(.is-dragging) .hm-card:hover { border-color: var(--hm-rule-2); }
.hm-rail:not(.is-dragging) .hm-card:active { transform: scale(0.982); }
.hm-card:focus-visible { outline: 2px solid var(--hm-accent); outline-offset: 3px; }

/* The app mark, shared by the rail card and the dashboard tile.
 *
 * Glyph names are the ones in js/shared/app-registry.js, so a module is
 * recognisable by the same symbol here, in the launcher flyout and in its own
 * app shell. Hairline square rather than a filled chip — the same treatment as
 * .hm-railbtn — so it reads as part of the editorial layer rather than a badge
 * bolted onto it, and the numerals keep doing their job beside it. */
.hm-tile-icon,
.hm-card-icon {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border: 1px solid var(--hm-rule);
    border-radius: 11px;
    color: var(--hm-ink-2);
    background: var(--hm-paper);
    transition: color var(--hm-quick) var(--hm-ease),
                border-color var(--hm-quick) var(--hm-ease),
                background var(--hm-quick) var(--hm-ease);
}

.hm-tile-icon { margin-bottom: 14px; }

.hm-tile-icon .material-symbols-outlined,
.hm-card-icon .material-symbols-outlined { font-size: 20px; }

.hm-tile:hover .hm-tile-icon,
.hm-rail:not(.is-dragging) .hm-card:hover .hm-card-icon {
    color: var(--hm-accent);
    border-color: var(--hm-accent);
    background: var(--hm-accent-soft);
}

/* The mark takes the left of the top row and the numeral (plus the flagship
   flag, where there is one) sits out to the right. `baseline` was right when
   the row held only text; with a 38px box in it, centre is. */
.hm-card-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 18px;
}

.hm-card-idx {
    margin-left: auto;   /* holds idx + flag together on the right */
    font-size: var(--hm-t-micro);
    font-weight: 620;
    letter-spacing: 0.1em;
    color: var(--hm-ink-3);
}

.hm-card-flag {
    font-size: var(--hm-t-micro);
    font-weight: 620;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--hm-accent);
}

.hm-card-title { margin-bottom: 8px; }

.hm-card-desc {
    font-size: var(--hm-t-small);
    line-height: 1.5;
    color: var(--hm-ink-2);
    /* Four lines keeps every card the same height without truncating any of
       the descriptions the locale files actually ship. */
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.hm-card-go {
    margin-top: auto;
    padding-top: 18px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: var(--hm-t-small);
    font-weight: 540;
    color: var(--hm-accent);
}

.hm-card-go svg { transition: transform var(--hm-quick) var(--hm-ease); }
.hm-rail:not(.is-dragging) .hm-card:hover .hm-card-go svg { transform: translateX(3px); }

/* --- Rail progress ------------------------------------------------------- */

.hm-rail-foot {
    display: flex;
    align-items: center;
    gap: 18px;
    margin-top: 24px;
}

.hm-rail-progress {
    position: relative;
    flex: 1;
    height: 2px;
    background: var(--hm-rule);
    border-radius: 2px;
    overflow: hidden;
}

.hm-rail-thumb {
    position: absolute;
    inset-block: 0;
    left: 0;
    background: var(--hm-ink);
    border-radius: 2px;
    transform-origin: left center;
    will-change: transform;
}

.hm-rail-steps { display: flex; gap: 6px; }

.hm-railbtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border: 1px solid var(--hm-rule);
    border-radius: 999px;
    background: none;
    color: var(--hm-ink);
    cursor: pointer;
    transition: background var(--hm-quick) var(--hm-ease),
                opacity var(--hm-quick) var(--hm-ease),
                transform var(--hm-quick) var(--hm-ease);
}

.hm-railbtn:hover { background: var(--hm-paper-2); }
.hm-railbtn:active { transform: scale(0.9); }
.hm-railbtn[disabled] { opacity: 0.32; pointer-events: none; }

/* ==========================================================================
   7. Differentiators — the three things nobody else here has
   ========================================================================== */

.hm-diff {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 264px), 1fr));
    gap: 0;
    border-top: 1px solid var(--hm-rule-2);
}

.hm-diff-item {
    padding: clamp(28px, 3.4vw, 40px) clamp(20px, 2.4vw, 32px) clamp(28px, 3.4vw, 40px) 0;
    border-right: 1px solid var(--hm-rule);
}

.hm-diff-item:last-child { border-right: 0; }

@media (max-width: 719px) {
    .hm-diff-item { border-right: 0; padding-right: 0; }
    .hm-diff-item + .hm-diff-item { border-top: 1px solid var(--hm-rule); }
}

/* Every column leads with a block of the same height, bottom-aligned, so the
   three titles share one baseline however tall each lead happens to be. */
.hm-glyphs,
.hm-diff-lead {
    display: flex;
    align-items: flex-end;
    min-height: 2.9rem;
    margin-bottom: 18px;
}

/* Cantonese particles set large are the most honest possible illustration of
   "Cantonese-first" — it is the product feature, rendered as type. */
.hm-glyphs {
    gap: 10px;
    font-size: clamp(1.9rem, 3.6vw, 2.6rem);
    font-weight: 500;
    line-height: 1;
    letter-spacing: 0.02em;
    color: var(--hm-ink);
}

.hm-glyphs span:nth-child(even) { color: var(--hm-ink-3); }

/* One non-wrapping line, so its height never changes and the baseline holds. */
.hm-diff-lead {
    font-size: var(--hm-t-micro);
    font-weight: 600;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--hm-ink-3);
    white-space: nowrap;
    overflow: hidden;
}

.hm-diff-title { margin-bottom: 10px; }

/* ==========================================================================
   8. Capability list — a ruled index, not a wall of cards
   ========================================================================== */

.hm-index { border-top: 1px solid var(--hm-rule-2); }

.hm-index-row {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: clamp(16px, 2.5vw, 32px);
    row-gap: 6px;
    padding-block: clamp(22px, 2.6vw, 30px);
    border-bottom: 1px solid var(--hm-rule);
}

.hm-index-n { grid-column: 1 / -1; color: var(--hm-ink-3); }
.hm-index-t { grid-column: 1 / -1; }
.hm-index-d { grid-column: 1 / -1; }

@media (min-width: 820px) {
    .hm-index-n { grid-column: 1 / 2; padding-top: 5px; }
    .hm-index-t { grid-column: 2 / 6; }
    .hm-index-d { grid-column: 6 / -1; }
}

.hm-index-t {
    font-size: var(--hm-t-lede);
    font-weight: 600;
    letter-spacing: -0.018em;
    line-height: 1.3;
}

/* ==========================================================================
   9. Model roster — a colophon / spec sheet
   ========================================================================== */

.hm-roster {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr));
    gap: 0;
    border-top: 1px solid var(--hm-rule-2);
}

.hm-roster-col {
    padding: 26px clamp(18px, 2vw, 28px) 26px 0;
    border-right: 1px solid var(--hm-rule);
}

.hm-roster-col:last-child { border-right: 0; }

@media (max-width: 719px) {
    .hm-roster-col { border-right: 0; padding-right: 0; }
    .hm-roster-col + .hm-roster-col { border-top: 1px solid var(--hm-rule); }
}

.hm-roster-head {
    font-size: var(--hm-t-micro);
    font-weight: 620;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--hm-ink-3);
    margin-bottom: 16px;
}

.hm-roster-list { display: flex; flex-direction: column; }

.hm-roster-list li {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding-block: 8px;
    font-size: var(--hm-t-small);
    line-height: 1.4;
}

.hm-roster-list li + li { border-top: 1px solid var(--hm-rule); }

.hm-roster-tag {
    flex: none;
    font-size: var(--hm-t-micro);
    letter-spacing: 0.04em;
    color: var(--hm-ink-3);
}

.hm-roster-tag--lit { color: var(--hm-accent); }

.hm-roster-note {
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--hm-rule);
    font-size: var(--hm-t-micro);
    line-height: 1.6;
    color: var(--hm-ink-3);
}

/* ==========================================================================
   10. Steps
   ========================================================================== */

.hm-steps { border-top: 1px solid var(--hm-rule-2); max-width: 860px; }

.hm-step {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: clamp(20px, 3vw, 40px);
    padding-block: clamp(26px, 3vw, 36px);
    border-bottom: 1px solid var(--hm-rule);
}

.hm-step-num {
    font-size: clamp(1.6rem, 3vw, 2.25rem);
    font-weight: 300;
    letter-spacing: -0.03em;
    line-height: 1;
    color: var(--hm-ink-3);
    min-width: 1.4em;
}

.hm-step-title { margin-bottom: 8px; }

/* ==========================================================================
   11. Trust
   ========================================================================== */

.hm-trust { display: grid; gap: 0; border-top: 1px solid var(--hm-rule-2); }

.hm-trust-row {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: clamp(16px, 2.5vw, 32px);
    row-gap: 8px;
    padding-block: clamp(24px, 2.8vw, 32px);
    border-bottom: 1px solid var(--hm-rule);
}

.hm-trust-t { grid-column: 1 / -1; font-weight: 600; letter-spacing: -0.014em; }
.hm-trust-d { grid-column: 1 / -1; }

@media (min-width: 820px) {
    .hm-trust-t { grid-column: 1 / 5; }
    .hm-trust-d { grid-column: 5 / -1; }
}

.hm-never { color: var(--hm-accent); font-weight: 620; }

/* ==========================================================================
   12. Closing CTA
   ========================================================================== */

.hm-close {
    border-top: 1px solid var(--hm-rule-2);
    padding-block: clamp(72px, 10vw, 132px);
    text-align: center;
}

.hm-close-actions {
    margin-top: 32px;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 12px;
}

/* ==========================================================================
   13. Footer — colophon
   ========================================================================== */

.hm-foot {
    border-top: 1px solid var(--hm-rule);
    background: var(--hm-paper-2);
    padding-block: clamp(48px, 6vw, 72px) 32px;
}

.hm-foot-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr));
    gap: clamp(28px, 4vw, 48px);
}

.hm-foot-lead { grid-column: 1 / -1; max-width: 34em; }

@media (min-width: 900px) { .hm-foot-lead { grid-column: span 2; } }

.hm-foot-head {
    font-size: var(--hm-t-micro);
    font-weight: 620;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--hm-ink-3);
    margin-bottom: 14px;
}

.hm-foot-list { display: flex; flex-direction: column; gap: 9px; }

.hm-foot-list a {
    font-size: var(--hm-t-small);
    color: var(--hm-ink-2);
    transition: color var(--hm-quick) var(--hm-ease);
}

.hm-foot-list a:hover { color: var(--hm-ink); }

.hm-foot-base {
    margin-top: clamp(40px, 5vw, 56px);
    padding-top: 22px;
    border-top: 1px solid var(--hm-rule);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    font-size: var(--hm-t-micro);
    color: var(--hm-ink-3);
}

/* ==========================================================================
   14. Signed-in dashboard
   ========================================================================== */

.hm-dash { padding-block: clamp(40px, 6vw, 72px) clamp(56px, 8vw, 96px); }

.hm-dash-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 214px), 1fr));
    gap: 12px;
    margin-top: clamp(28px, 4vw, 40px);
}

.hm-tile {
    display: flex;
    flex-direction: column;
    min-height: 150px;
    padding: 18px;
    border: 1px solid var(--hm-rule);
    border-radius: 16px;
    background: var(--hm-raise);
    color: inherit;
    transition: border-color var(--hm-quick) var(--hm-ease),
                transform var(--hm-quick) var(--hm-ease);
}

.hm-tile:hover { border-color: var(--hm-rule-2); }
.hm-tile:active { transform: scale(0.975); }
.hm-tile:focus-visible { outline: 2px solid var(--hm-accent); outline-offset: 3px; }

.hm-tile-title { font-size: 1rem; font-weight: 600; letter-spacing: -0.015em; }
.hm-tile-desc { margin-top: 5px; font-size: var(--hm-t-small); color: var(--hm-ink-2); line-height: 1.45; }

.hm-tile-go {
    margin-top: auto;
    padding-top: 16px;
    font-size: var(--hm-t-micro);
    font-weight: 560;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--hm-accent);
}

.hm-dash-account {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    margin-top: 36px;
    padding-top: 18px;
    border-top: 1px solid var(--hm-rule);
}

@media (min-width: 640px) { .hm-dash-account { display: none; } }

.hm-dash-account .hm-navlink { padding-block: 11px; }

/* ==========================================================================
   15. Generated FAQ block
   Emitted by packages/contracts/scripts/seo-canonical.mjs with .card/.display
   and Tailwind utilities, and regenerated by `npm run seo` — so it is restyled
   from the outside here rather than hand-edited.
   ========================================================================== */

#faq { max-width: var(--hm-max); margin-inline: auto; padding: clamp(64px, 8vw, 104px) var(--hm-gutter); }
#faq > .eyebrow { display: none; }

#faq h2 {
    font-size: var(--hm-t-h2) !important;
    font-weight: 660;
    line-height: 1.04;
    letter-spacing: -0.028em;
    margin-bottom: clamp(32px, 4vw, 48px);
}

#faq .grid { display: block; border-top: 1px solid var(--hm-rule-2); }

#faq details.card {
    background: none;
    border: 0;
    border-bottom: 1px solid var(--hm-rule);
    border-radius: 0;
    box-shadow: none;
    padding: 0;
}

#faq details.card:hover { background: none; box-shadow: none; transform: none; }

#faq summary {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 20px;
    padding-block: clamp(18px, 2.2vw, 24px);
    font-size: var(--hm-t-lede) !important;
    font-weight: 580;
    letter-spacing: -0.014em;
    line-height: 1.35;
    list-style: none;
}

#faq summary::-webkit-details-marker { display: none; }

#faq summary::after {
    content: "+";
    flex: none;
    font-size: 1.25rem;
    font-weight: 300;
    line-height: 1;
    color: var(--hm-ink-3);
    transition: transform var(--hm-lift) var(--hm-ease);
}

#faq details[open] summary::after { transform: rotate(45deg); }

#faq details p {
    margin-top: 0 !important;
    padding-bottom: clamp(20px, 2.4vw, 26px);
    max-width: 62ch;
    font-size: var(--hm-t-body) !important;
    line-height: 1.62;
    color: var(--hm-ink-2) !important;
}

/* ==========================================================================
   16. Entrance reveal
   ========================================================================== */

/* Hidden ONLY while `.hm-anim` is on <html>. That class is set by an inline
   head script and removed again by a watchdog if home.js never reports in, so
   a module-script failure can never leave half the page invisible — the
   sections simply render without the entrance. */
.hm-anim .hm-reveal {
    opacity: 0;
    transform: translate3d(0, 14px, 0);
    transition: opacity var(--hm-reveal) var(--hm-ease),
                transform var(--hm-reveal) var(--hm-ease);
}

.hm-anim .hm-reveal.is-in { opacity: 1; transform: none; }

/* ==========================================================================
   16b. Keyboard focus + touch hit areas

   The page had :focus-visible rings on four components (brand, button, card,
   tile) and none on the rest of the interactive surface. That left the
   notification bell and the theme toggle - the only routes to either feature -
   with no visible focus at all, and the account / export / clear / sign-out
   links, the rail arrows, the trust-section arrow and every footer link with
   nothing for a keyboard user to follow. One rule per selector rather than a
   blanket `*:focus-visible`, so the shape stays per-component.
   ========================================================================== */

.hm-iconbtn:focus-visible,
.hm-navlink:focus-visible,
.hm-railbtn:focus-visible,
.hm-arrowlink:focus-visible,
.hm-foot-list a:focus-visible,
.hm-mobilebar a:focus-visible,
.hm-dash-account .hm-navlink:focus-visible {
    outline: 2px solid var(--hm-accent);
    outline-offset: 3px;
    border-radius: 6px;
}

/* The FAQ disclosure is a <summary> inside the generated Tailwind block, and
   nothing in this file styles it. Without this the only focus affordance is
   whatever the UA default is, which the utility shims below can neutralise. */
#faq summary:focus-visible {
    outline: 2px solid var(--hm-accent);
    outline-offset: 3px;
    border-radius: 6px;
}

/* Touch hit areas. .hm-iconbtn is 36px and .hm-railbtn 34px - both under the
   44px minimum. The visual size is a design decision and stays; only the
   touch target grows, done with padding plus an equal negative margin so the
   layout does not shift and the row cannot start wrapping at 320px. Gated on
   pointer: coarse so a mouse user never gets a stray 8px of clickable gutter. */
@media (pointer: coarse) {
    .hm-iconbtn {
        width: 44px;
        height: 44px;
        margin: -4px;
    }

    .hm-railbtn {
        width: 44px;
        height: 44px;
        margin: -5px;
    }

    /* The nav links are text-only with padding:0; give the row a 44px band. */
    .hm-navlink {
        padding-block: 12px;
        margin-block: -12px;
    }

    .hm-foot-list a {
        display: inline-block;
        padding-block: 6px;
    }
}

/* ==========================================================================
   17. Accessibility preferences
   Reduced motion is not "no feedback" — it keeps the opacity change that
   tells you something arrived, and drops only the vestibular part.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }

    .hm-reveal {
        transform: none;
        transition: opacity 140ms ease;
    }

    .hm-btn:active,
    .hm-iconbtn:active,
    .hm-tile:active,
    .hm-railbtn:active,
    .hm-rail:not(.is-dragging) .hm-card:active { transform: none; }

    .hm-arrowlink:hover svg,
    .hm-card:hover .hm-card-go svg { transform: none; }

    .hm-rail-thumb { transition: none; }
}

@media (prefers-reduced-transparency: reduce) {
    .hm-nav {
        background: var(--hm-paper);
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
    }
}

@media (prefers-contrast: more) {
    :root {
        --hm-rule: rgba(22, 22, 26, 0.34);
        --hm-rule-2: rgba(22, 22, 26, 0.55);
        --hm-ink-2: #34343a;
        --hm-ink-3: #4c4c54;
    }

    html.dark {
        --hm-rule: rgba(244, 244, 242, 0.38);
        --hm-rule-2: rgba(244, 244, 242, 0.62);
        --hm-ink-2: #d2d2d6;
        --hm-ink-3: #b4b4bb;
    }

    .hm-nav {
        background: var(--hm-paper);
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
    }

    .hm-card, .hm-tile, .hm-router { border-color: var(--hm-rule-2); }
}

/* ==========================================================================
   18. Utility shims for the shared components
   --------------------------------------------------------------------------
   This page does NOT load js/shared/tailwind-browser.js (a 275 KB runtime JIT
   that has to parse the DOM and generate CSS before styles settle — the single
   heaviest thing on the landing page, and a visible FOUC). Its own markup uses
   no utility classes at all.

   The shared components it mounts still emit a handful, so those are declared
   statically here. The list is small because the real styling already lives in
   proper stylesheets: app-shell.css owns the launcher, notification panel and
   dashboard feed; modal.css owns the modal's surface, animation and buttons;
   and the generated FAQ block is restyled by the #faq rules above.

   `.hidden` is the load-bearing one — the launcher flyout and notification
   panel are `display:none` by that class alone, so without it they would render
   permanently open.

   COUPLING: derived from the classes emitted by modal-client.js, app-launcher.js,
   notification-center.js, dashboard-feed.js, error-client.js, ui-utils.js and
   the seo-canonical.mjs FAQ template. If one of those starts emitting a new
   utility, add it here. Colours are mapped to this page's tokens rather than
   Tailwind's grays, so the modal matches the editorial palette instead of
   fighting it.
   ========================================================================== */

.hidden { display: none; }

.opacity-0 { opacity: 0; }
.opacity-100 { opacity: 1; }

/* Layout — modal body/footer and the generated FAQ wrapper. */
.flex { display: flex; }
.flex-col { flex-direction: column; }
.flex-1 { flex: 1 1 0%; }
.flex-none { flex: none; }
.items-center { align-items: center; }
.justify-end { justify-content: flex-end; }
.gap-3 { gap: 0.75rem; }
.grid { display: grid; }
.grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
.relative { position: relative; }
.w-full { width: 100%; }
.min-h-0 { min-height: 0; }
.overflow-y-auto { overflow-y: auto; }
.text-left { text-align: left; }
.space-y-1 > * + * { margin-top: 0.25rem; }
.mx-auto { margin-inline: auto; }
.max-w-2xl { max-width: 42rem; }
.max-w-7xl { max-width: var(--hm-max); }
.cursor-pointer { cursor: pointer; }
.whitespace-pre-line { white-space: pre-line; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Spacing */
.mb-5 { margin-bottom: 1.25rem; }
.mb-6 { margin-bottom: 1.5rem; }
.mb-8 { margin-bottom: 2rem; }
.mb-10 { margin-bottom: 2.5rem; }
.mt-3 { margin-top: 0.75rem; }
.mr-2 { margin-right: 0.5rem; }
.mr-4 { margin-right: 1rem; }
.px-1 { padding-inline: 0.25rem; }
.px-4 { padding-inline: 1rem; }
.px-5 { padding-inline: 1.25rem; }
.px-7 { padding-inline: 1.75rem; }
.pr-2 { padding-right: 0.5rem; }
.py-2\.5 { padding-block: 0.625rem; }
.py-3 { padding-block: 0.75rem; }
.py-20 { padding-block: 5rem; }
.p-5 { padding: 1.25rem; }

/* Type */
.text-2xl { font-size: 1.5rem; line-height: 1.25; }
.text-base { font-size: 1rem; }
.text-\[14px\] { font-size: 14px; }
.text-\[15px\] { font-size: 15px; }
.text-\[17px\] { font-size: 17px; }
.text-\[20px\] { font-size: 20px; }
.text-\[24px\] { font-size: 24px; }
.font-medium { font-weight: 500; }
.font-semibold { font-weight: 600; }
.font-bold { font-weight: 700; }
.leading-relaxed { line-height: 1.625; }
.tracking-tight { letter-spacing: -0.025em; }

/* Colour — mapped to this page's ramp, not Tailwind's grays. */
.text-gray-900 { color: var(--hm-ink); }
.text-gray-600 { color: var(--hm-ink-2); }
.text-gray-500 { color: var(--hm-ink-3); }
.text-white { color: #fff; }
.bg-gray-50 { background: var(--hm-paper-2); }
html.dark .dark\:text-white { color: var(--hm-ink); }
html.dark .dark\:text-gray-300 { color: var(--hm-ink-2); }
html.dark .dark\:text-gray-400 { color: var(--hm-ink-3); }

/* Deliberately NOT shimmed: the arbitrary-value colour utilities modal-client.js
   puts on the dialog buttons and the prompt input —
   `bg-[#385bc9]`, `dark:bg-[#b2c7f6]`, `dark:text-[#1c306b]`, `dark:bg-[#1e1f20]`,
   `hover:bg-gray-100`, `dark:hover:bg-[#3c4043]`.
   modal.css styles those elements through ID selectors (`#modal-confirm`,
   `#modal-cancel`, `#modal-input`), which outrank any class rule — so those
   utilities never applied on ANY page in the suite, Tailwind or not. Shimming
   them here would add CSS that can never win and imply the dialog looks
   different on this page than everywhere else. It does not. */

/* Shape + transition */
.rounded-full { border-radius: 999px; }
.rounded-2xl { border-radius: 16px; }
.transition-all { transition: all var(--hm-quick) var(--hm-ease); }
.transition-colors {
    transition: color var(--hm-quick) var(--hm-ease),
                background-color var(--hm-quick) var(--hm-ease),
                border-color var(--hm-quick) var(--hm-ease);
}

@media (min-width: 768px) {
    .md\:p-6 { padding: 1.5rem; }
    .md\:px-6 { padding-inline: 1.5rem; }
    .md\:py-28 { padding-block: 7rem; }
}

/* Sits above the mobile action bar so the last row is never covered.
   The bar is `position: fixed` to the viewport, so what it overlaps is
   whatever ends the document — and since the footer moved out of <main> to be
   a direct child of <body> (so it is a real contentinfo landmark in BOTH the
   signed-out and signed-in states), that is now always the footer's last row,
   not the end of #main-interface. */
@media (max-width: 767px) {
    .hm-foot { padding-bottom: 84px; }
}

.hm-mobilebar {
    position: fixed;
    inset-inline: 16px;
    bottom: calc(14px + env(safe-area-inset-bottom, 0px));
    z-index: 40;
    display: flex;
    justify-content: center;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.14);
}

@media (min-width: 768px) { .hm-mobilebar { display: none; } }

body.spcy-consent-open .hm-mobilebar { display: none !important; }
