/* ─────────────────────────────────────────────────────────────────────────
   RECATOOLS · 万年历 Chinese Lunisolar Calendar (RT-CHN-107)

   Extends public/assets/css/oriental.css — it does not restate it. Load
   oriental.css FIRST; every colour here comes from that file's tokens
   (--o-ink, --o-paper, --o-seal, --o-gold, --o-jade) so the Art of War
   series and this tool cannot drift apart.

   THE DESIGN ARGUMENT, so a later session knows what to preserve:

   The ornament IS the computation. The hero is a wheel of the 24 节气 drawn
   at their TRUE solar longitudes — 15° apart, because that is the definition
   of a 节气, not a decorative choice. 冬至 sits at the bottom, 夏至 at the
   top, the equinoxes on the horizontal, which is the Sun's own geometry. The
   marker on the arc is where the Sun actually is today. Nothing on the wheel
   is drawn for looks; it is a plot, and it is beautiful because it is true.

   Restraint is the whole style. Paper and ink do the work. Cinnabar appears
   ONCE per view — on the seal, or on the marker, never both prominently —
   and antique gold only as a hairline. No dragons, no lanterns, no knots, no
   gradients, no red-and-gold. If an element does not carry information, it is
   not here.

   MOBILE IS THE DESIGN, NOT THE FALLBACK. ~93% of this tool's audience is on
   a phone in a CN webview. The wheel is sized and labelled for 375px first;
   the desktop version adds labels it has room for, and that is the only
   difference. Every layout below is single-column until it has earned a
   second one.
   ───────────────────────────────────────────────────────────────────────── */

/* ── Layout shell ──────────────────────────────────────────────────────── */

.ls {
    --ls-gap: 14px;
    --ls-radius: 3px;
    display: flex;
    flex-direction: column;
    gap: var(--ls-gap);
    font-family: var(--o-serif);
    color: var(--o-ink);
}

.ls-han { font-family: var(--o-han); }
.ls-mono { font-family: var(--o-mono); }

/* Screen-reader-only, local to the widget so it never depends on the shell. */
.ls-sr {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* ── The control bar — input first, per the tool-first rule ────────────── */

/* TWO COLUMNS ON A PHONE, and that is a measured decision rather than a
   preference. Stacked one-per-row the four controls came to 299px, which put
   the day number — the answer someone came for — at y=806 on a 812px screen.
   Exactly at the fold, so a reader converting a birthday saw a form and had to
   scroll to find out it had worked. Two-up costs nothing legible (the date
   still spans the full width, where the native picker needs it) and lifts the
   answer ~100px clear. */
.ls-controls {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px 12px;
    padding: 13px;
    border: 1px solid var(--o-line);
    border-radius: var(--ls-radius);
    background-color: rgba(255, 253, 246, .55);
}

.ls-field--date { grid-column: 1 / -1; }
.ls-controls .ls-today { grid-column: 1 / -1; }

@media (min-width: 620px) {
    .ls-controls { grid-template-columns: 1.4fr .9fr 1fr auto; align-items: end; }
    .ls-field--date,
    .ls-controls .ls-today { grid-column: auto; }
}

.ls-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }

.ls-label {
    font-family: var(--o-mono);
    font-size: 10px;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--o-ink-faint);
}

.ls-input,
.ls-select {
    font-family: var(--o-mono);
    font-size: 15px;
    color: var(--o-ink);
    background: rgba(255, 253, 246, .9);
    border: 0;
    border-bottom: 1.5px solid var(--o-line);
    border-radius: 0;
    padding: 9px 4px;
    /* 44px minimum tap target — the site-wide mobile rule. */
    min-height: 44px;
    width: 100%;
    appearance: none;
    -webkit-appearance: none;
}

.ls-select {
    /* A hand-drawn chevron rather than the platform one, so the control reads
       as part of the sheet. Inline data URI — no icon font, no request. */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='7'%3E%3Cpath d='M1 1l4.5 4.4L10 1' fill='none' stroke='%235d574c' stroke-width='1.4' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 6px center;
    padding-right: 24px;
}

.ls-input:focus,
.ls-select:focus {
    outline: none;
    border-bottom-color: var(--o-seal);
    box-shadow: 0 1px 0 0 var(--o-seal);
}

.ls-today {
    font-family: var(--o-han);
    font-size: 14px;
    color: var(--o-ink-soft);
    background: transparent;
    border: 1px solid var(--o-line);
    border-radius: var(--ls-radius);
    padding: 0 16px;
    min-height: 44px;
    cursor: pointer;
    white-space: nowrap;
    transition: background-color .16s, color .16s;
}

.ls-today:hover { background: var(--o-paper-2); }

/* ── The refusal, when a date falls outside the supported range ────────── */

.ls-refusal {
    border: 1px solid rgba(157, 43, 37, .38);
    border-left: 3px solid var(--o-seal);
    border-radius: var(--ls-radius);
    background: rgba(157, 43, 37, .05);
    padding: 12px 14px;
    font-size: 14px;
    line-height: 1.62;
    color: var(--o-ink-2);
}

.ls-refusal strong { color: var(--o-seal); }

/* ── The main pane: tear-off sheet + wheel ─────────────────────────────── */

.ls-main {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--ls-gap);
}

/* The sheet leads on mobile — someone converting a birthday wants the answer,
   not the ornament. On a wide screen they sit side by side and the wheel
   takes the larger share, because there it is legible enough to be read. */
@media (min-width: 900px) {
    .ls-main { grid-template-columns: minmax(0, 300px) minmax(0, 1fr); align-items: start; }
}

/* ── 撕页 — the tear-off almanac sheet ─────────────────────────────────── */

.ls-sheet {
    position: relative;
    background-color: #fdfaf0;
    background-image:
        radial-gradient(120% 60% at 50% 0%, rgba(255, 255, 255, .9) 0%, rgba(255, 255, 255, 0) 60%),
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.38'/%3E%3C/svg%3E");
    background-blend-mode: normal, multiply;
    border: 1px solid var(--o-line);
    border-top: 0;
    border-radius: 0 0 var(--ls-radius) var(--ls-radius);
    box-shadow: 0 14px 30px rgba(22, 21, 15, .1);
    padding: 0 16px 16px;
    overflow: hidden;
}

/* The torn top edge. An SVG mask rather than a zigzag border, so the tear is
   irregular the way a real one is. Fixed height, so it reserves its own space
   and cannot shift anything below it. */
.ls-sheet-tear {
    display: block;
    width: 100%;
    height: 13px;
    margin-bottom: 4px;
}

.ls-sheet-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--o-line-soft);
}

.ls-sheet-ym {
    font-family: var(--o-mono);
    font-size: 12px;
    letter-spacing: .1em;
    color: var(--o-ink-soft);
}

.ls-sheet-week {
    font-family: var(--o-han);
    font-size: 14px;
    color: var(--o-ink-soft);
}

/* The big day number. This is the element a reader's eye lands on. */
.ls-day {
    font-family: var(--o-serif);
    font-size: clamp(78px, 24vw, 122px);
    line-height: .92;
    letter-spacing: -.03em;
    text-align: center;
    color: var(--o-ink);
    margin: 10px 0 2px;
    /* Tabular figures so 1 and 11 do not jump the layout on change. */
    font-variant-numeric: tabular-nums;
}

.ls-day--festival { color: var(--o-seal); }

.ls-lunar {
    font-family: var(--o-han);
    font-size: 25px;
    /* Room for the ruby line above the characters. */
    margin-top: 6px;
    text-align: center;
    letter-spacing: .06em;
    color: var(--o-ink-2);
}

.ls-lunar-leap {
    color: var(--o-seal);
    font-size: .8em;
    vertical-align: .12em;
}

.ls-sheet-festival {
    margin-top: 9px;
    text-align: center;
    font-family: var(--o-han);
    font-size: 15px;
    color: var(--o-seal);
    line-height: 1.5;
}

.ls-sheet-festival:empty { display: none; }

.ls-holiday-chip {
    display: inline-block;
    font-family: var(--o-mono);
    font-size: 9px;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: #fdf6ec;
    background: var(--o-seal);
    border-radius: 2px;
    padding: 1px 5px;
    margin-left: 5px;
    vertical-align: .12em;
}

/* ── The four pillars, set vertically the way an almanac sets them ─────── */

.ls-pillars {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 6px;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--o-line-soft);
}

.ls-pillar {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
}

.ls-pillar-label {
    font-family: var(--o-mono);
    font-size: 9px;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--o-ink-faint);
}

/* Vertical CJK — a real typographic move, not a costume: this is how the
   四柱 are set in every almanac, one column per pillar. */
.ls-pillar-gz {
    font-family: var(--o-han);
    font-size: 21px;
    line-height: 1.14;
    writing-mode: vertical-rl;
    text-orientation: upright;
    letter-spacing: .04em;
    color: var(--o-ink);
    border: 1px solid var(--o-line-soft);
    border-radius: 2px;
    padding: 6px 3px;
    background: rgba(255, 253, 246, .6);
    min-height: 62px;
}

.ls-pillar--disputed .ls-pillar-gz {
    border-color: rgba(157, 43, 37, .5);
    border-style: dashed;
}

.ls-pillar--empty .ls-pillar-gz {
    color: var(--o-ink-faint);
    border-style: dashed;
}

/* ── The wheel ─────────────────────────────────────────────────────────── */

.ls-wheel-wrap {
    position: relative;
    border: 1px solid var(--o-line);
    border-radius: var(--ls-radius);
    padding: 8px;
    background-color: rgba(255, 253, 246, .4);
}

/* The SVG carries its own aspect ratio through the viewBox, and the wrapper
   never changes size when the data does — the marker and the labels are
   painted INSIDE a box whose dimensions are fixed at parse time. That is why
   this hero contributes exactly zero to CLS despite being data-driven. */
.ls-wheel {
    display: block;
    width: 100%;
    height: auto;
}

.ls-wheel-ring { fill: none; stroke: var(--o-line); stroke-width: 1; }
.ls-wheel-season { stroke-width: 0; }
.ls-wheel-spring { fill: rgba(77, 107, 88, .09); }
.ls-wheel-summer { fill: rgba(168, 135, 60, .11); }
.ls-wheel-autumn { fill: rgba(157, 43, 37, .07); }
.ls-wheel-winter { fill: rgba(50, 46, 38, .07); }

.ls-tick { stroke: var(--o-ink-faint); stroke-width: 1; }
.ls-tick--major { stroke: var(--o-ink-soft); stroke-width: 1.6; }

.ls-wheel-label {
    font-family: var(--o-han);
    font-size: 15px;
    fill: var(--o-ink-soft);
    text-anchor: middle;
    dominant-baseline: middle;
}

.ls-wheel-label--major { fill: var(--o-ink); font-weight: 600; }

/* On a phone, 24 two-character labels round a 340px circle is 39px of arc
   each — legible only as a smear. So the minor terms drop out below 620px
   and the eight that name the seasons carry the ring. The ticks all stay:
   the geometry is still complete, only the lettering thins. */
.ls-wheel-label--minor { display: none; }
@media (min-width: 620px) { .ls-wheel-label--minor { display: block; } }

.ls-wheel-season-name {
    font-family: var(--o-han);
    font-size: 13px;
    fill: var(--o-ink-faint);
    text-anchor: middle;
    letter-spacing: .3em;
}

/* The marker — the one cinnabar element on the wheel. */
.ls-marker-line { stroke: var(--o-seal); stroke-width: 1; stroke-dasharray: 2 3; opacity: .75; }
.ls-marker-dot { fill: var(--o-seal); }
.ls-marker-halo { fill: none; stroke: var(--o-seal); stroke-width: 1; opacity: .35; }

.ls-wheel-centre-gz {
    font-family: var(--o-han);
    font-size: 30px;
    fill: var(--o-ink);
    text-anchor: middle;
    letter-spacing: .05em;
}

.ls-wheel-centre-sub {
    font-family: var(--o-mono);
    font-size: 11px;
    fill: var(--o-ink-faint);
    text-anchor: middle;
    letter-spacing: .12em;
}

.ls-wheel-centre-lon {
    font-family: var(--o-mono);
    font-size: 12px;
    fill: var(--o-seal);
    text-anchor: middle;
    letter-spacing: .06em;
}

.ls-wheel-caption {
    margin-top: 6px;
    font-family: var(--o-mono);
    font-size: 10.5px;
    line-height: 1.6;
    letter-spacing: .04em;
    color: var(--o-ink-faint);
    text-align: center;
}

/* ── Next-term strip ───────────────────────────────────────────────────── */

.ls-nextterm {
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--o-line-soft);
    font-size: 13px;
    color: var(--o-ink-soft);
}

.ls-nextterm-name { font-family: var(--o-han); font-size: 17px; color: var(--o-ink); }
.ls-nextterm-when { font-family: var(--o-mono); font-size: 12px; }

/* ── Disclosure cards — where the tool says what it does not know ──────── */

.ls-card {
    border: 1px solid var(--o-line);
    border-radius: var(--ls-radius);
    padding: 14px;
    background-color: rgba(255, 253, 246, .5);
}

.ls-card-title {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: var(--o-han);
    font-size: 16px;
    color: var(--o-ink);
    margin-bottom: 4px;
}

.ls-card-title::before {
    content: '';
    width: 3px;
    height: 15px;
    background: var(--o-ink-soft);
    flex: 0 0 auto;
}

.ls-card--alert { border-color: rgba(157, 43, 37, .42); background-color: rgba(157, 43, 37, .045); }
.ls-card--alert .ls-card-title::before { background: var(--o-seal); }

.ls-card-note {
    font-size: 13.5px;
    line-height: 1.66;
    color: var(--o-ink-soft);
}

/* ── The zodiac boundary — the correctness edge, given the most space ──── */

.ls-conventions {
    display: grid;
    grid-template-columns: 1fr;
    gap: 8px;
    margin-top: 12px;
}

@media (min-width: 560px) { .ls-conventions { grid-template-columns: repeat(3, 1fr); } }

.ls-conv {
    display: flex;
    flex-direction: column;
    gap: 3px;
    border: 1px solid var(--o-line-soft);
    border-radius: 2px;
    padding: 10px 11px;
    background: rgba(255, 253, 246, .75);
}

/* When the three disagree, the odd ones out are marked — with the seal, and
   only then. That is the one place cinnabar is spent on this card. */
.ls-conv--differs { border-color: rgba(157, 43, 37, .45); background: rgba(157, 43, 37, .04); }

.ls-conv-rule {
    font-family: var(--o-mono);
    font-size: 9.5px;
    letter-spacing: .11em;
    text-transform: uppercase;
    color: var(--o-ink-faint);
}

.ls-conv-animal {
    font-family: var(--o-han);
    font-size: 26px;
    line-height: 1.1;
    color: var(--o-ink);
}

.ls-conv--differs .ls-conv-animal { color: var(--o-seal); }

.ls-conv-gz { font-family: var(--o-han); font-size: 14px; color: var(--o-ink-soft); }
.ls-conv-when { font-family: var(--o-mono); font-size: 10.5px; color: var(--o-ink-faint); }

.ls-verdict {
    margin-top: 12px;
    padding: 11px 13px;
    border-radius: 2px;
    font-size: 13.5px;
    line-height: 1.66;
}

.ls-verdict--agree { background: rgba(77, 107, 88, .1); color: var(--o-ink-2); }
.ls-verdict--differ { background: rgba(157, 43, 37, .09); color: var(--o-ink-2); }
.ls-verdict strong { color: var(--o-ink); }

/* ── Jurisdictions ─────────────────────────────────────────────────────── */

.ls-juris {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 7px;
    margin-top: 12px;
}

@media (min-width: 560px) { .ls-juris { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 900px) { .ls-juris { grid-template-columns: repeat(6, minmax(0, 1fr)); } }

.ls-j {
    border: 1px solid var(--o-line-soft);
    border-radius: 2px;
    padding: 9px 10px;
    background: rgba(255, 253, 246, .72);
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.ls-j--differs { border-color: rgba(157, 43, 37, .45); background: rgba(157, 43, 37, .04); }

.ls-j-code {
    font-family: var(--o-mono);
    font-size: 10px;
    letter-spacing: .13em;
    color: var(--o-ink-faint);
}

.ls-j-lunar { font-family: var(--o-han); font-size: 16px; color: var(--o-ink); }
.ls-j--differs .ls-j-lunar { color: var(--o-seal); }
.ls-j-fest { font-family: var(--o-han); font-size: 12px; color: var(--o-ink-soft); line-height: 1.45; }
.ls-j-tz { font-family: var(--o-mono); font-size: 9.5px; color: var(--o-ink-faint); }

/* ── Age readout ───────────────────────────────────────────────────────── */

.ls-ages { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 10px; }

.ls-age {
    flex: 1 1 120px;
    border: 1px solid var(--o-line-soft);
    border-radius: 2px;
    padding: 9px 11px;
    background: rgba(255, 253, 246, .72);
}

.ls-age-n {
    font-family: var(--o-serif);
    font-size: 30px;
    line-height: 1;
    color: var(--o-ink);
    font-variant-numeric: tabular-nums;
}

.ls-age-label { font-family: var(--o-han); font-size: 13px; color: var(--o-ink-soft); }
.ls-age-sub { font-family: var(--o-mono); font-size: 10px; color: var(--o-ink-faint); margin-top: 2px; }

/* ── The year's 24 terms, as four seasons of six ───────────────────────── */

/* REPLACED a flat 4-column rail, and the reason is worth keeping. That grid
   put hanzi, ruby, gloss and instant on ONE line in a ~170px cell. Two things
   broke, both only at real widths:
     · the gloss truncated to "Minor ...", "Start of ..." — the single thing a
       non-Chinese reader needs from this block was the thing they could not
       read, and ms/id (longer) were worse;
     · the two-character term WRAPPED, so 小寒 came out as a stack reading
       xiǎo / 小 / hán / 寒 and the pinyin looked interleaved with the
       characters rather than set above them. It read as a rendering fault.
   Neither is fixable by shrinking text. The shape had to change: three stacked
   lines per term, so nothing shares a horizontal run with anything else. */

.ls-seasons { display: flex; flex-direction: column; gap: 16px; margin-top: 12px; }

.ls-season-h {
    display: flex;
    align-items: baseline;
    gap: 9px;
    margin: 0 0 8px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--o-line-soft);
    font-weight: 400;
}

/* The season character, set large and quiet — a mark, not a shout. */
.ls-season-glyph {
    font-family: var(--o-han);
    font-size: 21px;
    line-height: 1;
    color: var(--o-ink);
    letter-spacing: .1em;
}

.ls-season-name {
    font-family: var(--o-mono);
    font-size: 10px;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--o-ink-faint);
}

/* Two up on a phone, three from tablet. Never four — four is what caused the
   truncation, and the longest glosses (id: "Titik Balik Musim Dingin") need
   room to wrap onto a second line rather than being cut. */
.ls-season-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1px;
    background: var(--o-line-soft);
    border: 1px solid var(--o-line-soft);
    border-radius: 2px;
    overflow: hidden;
}

@media (min-width: 700px) {
    .ls-season-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.ls-tcard {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 11px 9px;
    background: rgba(255, 253, 246, .86);
    min-width: 0;
}

/* 二分二至 — the equinoxes and solstices. These are the astronomical anchors
   the entire system hangs off (the whole calendar is defined by where the Sun
   is relative to them), and in the old rail they looked exactly like the other
   twenty. A cinnabar edge and a slightly warmer ground, nothing louder. */
.ls-tcard--cardinal {
    background: rgba(157, 43, 37, .05);
    box-shadow: inset 2px 0 0 0 var(--o-seal);
}

.ls-tcard--now { background: rgba(168, 135, 60, .14); }
.ls-tcard--now.ls-tcard--cardinal { background: rgba(168, 135, 60, .18); }

/* THE ANNOTATED UNIT NEVER WRAPS. This is the rule the old layout broke: a
   two-character term splitting across lines puts each character's ruby on its
   own row and the reading appears to sit between the hanzi. The card is sized
   to fit it; the gloss below is what gives way instead. */
.ls-tcard-name {
    font-family: var(--o-han);
    font-size: 16px;
    line-height: 1.15;
    color: var(--o-ink);
    white-space: nowrap;
    /* Ruby overflows its line box upward — never clip it. */
    overflow: visible;
    /* Headroom for the annotation above the characters. */
    margin-top: 7px;
}

.ls-tcard-name ruby { white-space: nowrap; }

.ls-tcard--cardinal .ls-tcard-name { color: var(--o-seal); }

/* The gloss WRAPS and is never truncated — no ellipsis, no nowrap, no clip.
   Truncating it is the defect this whole block was rebuilt to fix. */
.ls-tcard-gloss {
    font-family: var(--o-serif);
    font-size: 11.5px;
    line-height: 1.42;
    color: var(--o-ink-soft);
    overflow-wrap: break-word;
    hyphens: none;
}

.ls-tcard-when {
    font-family: var(--o-mono);
    font-size: 10.5px;
    line-height: 1.4;
    color: var(--o-ink-faint);
    letter-spacing: .02em;
    /* Tabular figures so the dates form a column down the card stack. */
    font-variant-numeric: tabular-nums;
    margin-top: 1px;
    white-space: nowrap;
}

.ls-tcard--cardinal .ls-tcard-when { color: var(--o-ink-soft); }

/* ── The ink painting band ─────────────────────────────────────────────── */

/* Below the fold, lazy, and dimensioned. It is atmosphere, not information —
   so it must never be in the way of someone who came for a date. */
.ls-plate {
    position: relative;
    border: 1px solid var(--o-line);
    border-radius: var(--ls-radius);
    overflow: hidden;
    background: var(--o-paper-2);
}

.ls-plate img {
    display: block;
    width: 100%;
    height: auto;
    /* No aspect-ratio here on purpose: the <img> carries its true intrinsic
       width/height attributes (1200x669), from which the browser derives the
       ratio and reserves the box before a byte of the image arrives. Hard-
       coding 16/9 here would be a SECOND source of truth that silently
       disagrees with the file whenever the plate is re-encoded. */
    object-fit: cover;
}

.ls-plate-caption {
    position: absolute;
    left: 0; right: 0; bottom: 0;
    padding: 18px 14px 10px;
    font-family: var(--o-mono);
    font-size: 10px;
    letter-spacing: .1em;
    color: rgba(253, 246, 236, .82);
    background: linear-gradient(to top, rgba(22, 21, 15, .55), rgba(22, 21, 15, 0));
    text-align: right;
}

/* ── Seal, positioned as a chop is: bottom-right, slightly inset ───────── */

.ls-chop {
    position: absolute;
    right: 12px;
    bottom: 12px;
    pointer-events: none;
    opacity: .92;
}

/* ── Provenance line ───────────────────────────────────────────────────── */

.ls-provenance {
    font-family: var(--o-mono);
    font-size: 10.5px;
    line-height: 1.75;
    letter-spacing: .03em;
    color: var(--o-ink-faint);
    border-top: 1px solid var(--o-line-soft);
    padding-top: 10px;
}

.ls-provenance strong { color: var(--o-ink-soft); font-weight: 400; }

/* ── Pinyin: ruby annotation ───────────────────────────────────────────── */

/* The hierarchy, held everywhere:  hanzi = hero, pinyin = annotation,
   gloss = body. Three elements, three ranks, never three equals.

   Real <ruby>/<rt>, styled explicitly — the UA default is too large and sits
   too close, which is most of what makes ruby look bolted on rather than
   typeset. */

.ls ruby {
    ruby-position: over;
    -webkit-ruby-position: before;
}

.ls rt {
    /* 0.58em: it annotates, it never competes. */
    font-size: .58em;
    font-family: var(--o-mono);
    font-weight: 400;
    color: var(--o-ink-faint);
    /* TONE MARKS NEED HEADROOM. ǎ ě ǐ ǒ ǔ ǚ rise well above x-height, and a
       tight line-height CLIPS the caron — it reads as a rendering fault, and
       it is easy to miss because unmarked syllables look perfect. Test 芒种
       mángzhòng and 处暑 chǔshǔ, whose carons are the ones that clip. */
    line-height: 1.55;
    /* Latin against CJK sits cramped without a little tracking; the ideographs
       are full-width and the roman is not. Kept small — at .05em the longest
       readings overflowed the rail cell. */
    letter-spacing: .02em;
    text-align: center;
    white-space: nowrap;
}

/* No ancestor of a ruby may clip vertically, or the annotation goes with it. */
.ls-lunar,
.ls-tcard-name,
.ls-nextterm-name,
.ls-conv-animal { overflow: visible; }

/* The lead annotation — the lunar date on the sheet. */
.ls-lunar rt { font-size: .42em; color: var(--o-ink-soft); }

/* Gloss: body weight, in the reader's language, ranked below both. */
.ls-term-gloss,
.ls-conv-animal-py,
.ls-nextterm-py {
    font-family: var(--o-serif);
    font-size: 11.5px;
    color: var(--o-ink-soft);
    letter-spacing: .01em;
}


/* The 四柱 keep a caption rather than ruby: the columns are set vertically
   (writing-mode: vertical-rl) and ruby in vertical text is laid out to the
   side, which fights the grid at this size. A caption under each column reads
   cleanly and stays aligned. */
.ls-pillar-py {
    font-family: var(--o-mono);
    font-size: 8.5px;
    line-height: 1.4;
    letter-spacing: .03em;
    color: var(--o-ink-faint);
    text-align: center;
}

.ls-wheel-centre-py {
    font-family: var(--o-mono);
    font-size: 11px;
    fill: var(--o-ink-faint);
    text-anchor: middle;
    letter-spacing: .06em;
}

/* ── Share ─────────────────────────────────────────────────────────────── */

.ls-share {
    display: flex;
    align-items: center;
    gap: 9px;
    flex-wrap: wrap;
}

.ls-share-btn {
    font-family: var(--o-han);
    font-size: 14px;
    letter-spacing: .06em;
    color: #fdf6ec;
    background: linear-gradient(150deg, var(--o-seal-2), var(--o-seal));
    border: 0;
    border-radius: 2px;
    padding: 0 20px;
    min-height: 44px;
    cursor: pointer;
    box-shadow: inset 0 0 0 1px rgba(253, 246, 236, .35);
}

.ls-share-btn--ghost {
    background: transparent;
    color: var(--o-ink-soft);
    box-shadow: none;
    border: 1px solid var(--o-line);
}

.ls-share-btn--ghost:hover { background: var(--o-paper-2); }

.ls-share-flash {
    font-family: var(--o-mono);
    font-size: 11px;
    color: var(--o-ink-faint);
}

/* The card is rendered at its true 1080×1350 and parked off-screen, never
   display:none — html2canvas cannot rasterise a node with no layout box. */
.ls-card-holder {
    position: absolute;
    left: -20000px;
    top: 0;
    width: 1080px;
    height: 1350px;
    overflow: hidden;
    pointer-events: none;
}

/* ── The share card itself ─────────────────────────────────────────────── */

/* EVERY rule here is `.sc-card.ls-sc`, not `.ls-sc`. share-card.css defines
   `.sc-card { background: var(--sc-navy-card); color: var(--sc-cream) }` and
   loads AFTER this file, so a single-class selector loses the tie and the card
   exports navy-on-navy. Found by rendering one and looking at it — which is
   the only way this class of bug is ever found, because the markup, the
   JavaScript and the code review all look correct. */

/* Rice paper, not the platform navy: this card has to look like it came from
   an almanac, because that is the object a CN reader already recognises and
   forwards. Everything is set at card scale — this node is 1080px wide, so
   the type sizes below are ~3x what they would be on the page. */
.sc-card.ls-sc {
    background-color: #f4ecd9;
    background-image:
        radial-gradient(120% 70% at 50% 0%, rgba(255, 253, 246, .95) 0%, rgba(255, 253, 246, 0) 62%),
        radial-gradient(80% 60% at 100% 100%, rgba(196, 180, 146, .38) 0%, rgba(196, 180, 146, 0) 60%),
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23g)' opacity='0.42'/%3E%3C/svg%3E");
    background-blend-mode: normal, normal, multiply;
    color: #16150f;
    font-family: var(--o-han);
    padding: 92px 84px 88px;
    text-align: center;
    align-items: center;
}

/* Flex children must not be allowed to shrink. Without this the 260px day
   number is compressed by the flex algorithm and its glyphs ride up into the
   line above — which is exactly what the first export did. */
.sc-card.ls-sc > * { flex: 0 0 auto; width: 100%; }

.sc-card.ls-sc .ls-sc-rule {
    height: 5px;
    background: #16150f;
    width: 84px;
    margin: 0 auto 40px;
    flex-basis: 5px;
}

.sc-card.ls-sc .ls-sc-eyebrow {
    font-family: var(--o-mono);
    font-size: 23px;
    letter-spacing: .44em;
    text-transform: uppercase;
    color: #8d8578;
    margin: 0 0 26px;
    /* The tracking is applied to the right of the last glyph too, which pulls
       a centred line off-centre by half the tracking. Push it back. */
    text-indent: .44em;
}

.sc-card.ls-sc .ls-sc-greg {
    font-family: var(--o-mono);
    font-size: 32px;
    letter-spacing: .16em;
    color: #5d574c;
}

/* The single largest thing on the card. A day number reads at thumbnail size
   in a chat list, which is where this image is actually going to be seen. */
.sc-card.ls-sc .ls-sc-day {
    font-family: var(--o-serif);
    font-size: 220px;
    line-height: 1.0;
    letter-spacing: -.04em;
    color: #16150f;
    /* The separation is a MARGIN, not line-height. In the DOM the two boxes
       never overlapped even at line-height 1.02 — html2canvas lays text out
       itself and put the numeral's bowl through the lunar date anyway. A
       margin is the one thing both layout engines agree on. Verified by
       exporting the PNG and looking at it, which is the only way this is ever
       caught: the DOM measurement says the boxes are 4px apart and clean. */
    margin: 4px 0 26px;
    font-variant-numeric: tabular-nums;
}

.sc-card.ls-sc .ls-sc-lunar {
    font-size: 84px;
    letter-spacing: .1em;
    line-height: 1.24;
    color: #322e26;
}

.sc-card.ls-sc .ls-sc-lunar-py {
    font-family: var(--o-mono);
    font-size: 30px;
    letter-spacing: .1em;
    color: #8d8578;
    margin-top: 8px;
}

.sc-card.ls-sc .ls-sc-term {
    font-size: 42px;
    letter-spacing: .2em;
    line-height: 1.3;
    color: #9d2b25;
    margin-top: 20px;
    min-height: 55px;
    text-indent: .2em;
}

.sc-card.ls-sc .ls-sc-pillars {
    display: flex;
    justify-content: center;
    gap: 24px;
    margin-top: 38px;
}

.sc-card.ls-sc .ls-sc-pillar {
    font-size: 42px;
    line-height: 1.18;
    letter-spacing: .04em;
    writing-mode: vertical-rl;
    text-orientation: upright;
    border: 2px solid rgba(22, 21, 15, .3);
    padding: 18px 11px;
    background: rgba(255, 253, 246, .5);
    width: auto;
    color: #16150f;
}

.sc-card.ls-sc .ls-sc-note {
    font-size: 29px;
    line-height: 1.6;
    color: #5d574c;
    margin-top: 36px;
    padding: 0 8px;
}

/* The chop. One cinnabar element on the whole card, set in the lower-left
   margin the way a seal is stamped clear of the text column — NOT floating
   over the note, which is where an absolute bottom offset put it. */
.sc-card.ls-sc .ls-sc-seal {
    width: 112px;
    height: 112px;
    margin: 40px auto 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 40px;
    line-height: 1.04;
    font-weight: 700;
    color: #fdf6ec;
    background: linear-gradient(150deg, #bf3a2b, #9d2b25);
    box-shadow: inset 0 0 0 4px rgba(253, 246, 236, .55);
    border-radius: 4px;
    letter-spacing: .02em;
    white-space: pre-line;
    text-align: center;
}

.sc-card.ls-sc .sc-spacer { flex: 1 1 auto; min-height: 24px; }

.sc-card.ls-sc .ls-sc-footer {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    border-top: 2px solid rgba(22, 21, 15, .22);
    padding-top: 24px;
}

.sc-card.ls-sc .ls-sc-wordmark { font-family: var(--o-serif); font-size: 32px; color: #16150f; }
.sc-card.ls-sc .ls-sc-wordmark b { color: #9d2b25; font-weight: 400; }
.sc-card.ls-sc .ls-sc-url { font-family: var(--o-mono); font-size: 22px; letter-spacing: .04em; color: #8d8578; }

/* ── Motion ────────────────────────────────────────────────────────────── */

/* The marker eases to its new angle when the date changes. It is the only
   animation on the page, it is 240ms, and it exists because the wheel is a
   position — seeing it MOVE is how a reader understands that the date and the
   angle are the same fact. */
.ls-marker { transition: transform .24s cubic-bezier(.22, .61, .36, 1); }

@media (prefers-reduced-motion: reduce) {
    .ls-marker { transition: none; }
}
