/* Agoramores — "january" theme overrides. Loaded after main.css.
   Every selector here is scoped to body[data-theme-id="january"]. */

/* ===========================================================================
   JANUARY — deep midwinter, after the holidays are over.

   A flat white field under a washed-out overcast sky. One bare bough
   overhanging the top-right corner, a thin stand of dead stalks on the drift
   line, a wan sun that gives no heat, and a little wind-blown snow. That is the
   entire cast. Restraint is the concept, not a budget: this month has roughly a
   third of the decorative surface October and September carry, and the empty
   sky between the bough and the horizon is doing as much work as anything
   drawn.

   HOW IT AVOIDS BEING DECEMBER OR FEBRUARY. December is the holidays and
   February is love; both of those are warm months with a bright ornamental
   accent on a dark ground. January inverts the ground — it is the project's
   coldest and lightest theme, the sky occupies four fifths of the frame, and
   the only saturated colour on screen is a single winterberry red used
   sparingly enough to read as the one live thing in a dead field.

   THE RED ANCHOR ON A COLD MONTH. Agoramores is red-anchored every month, and
   a barren January could have argued its way out of that. It does not need to:
   the one colour that survives an Ohio January outdoors is the rose hip and the
   winterberry still clinging to a leafless shrub. --jan-rose is that berry. It
   leads every gradient, frames the card, marks today on the calendar, carries
   bold text and the table headers, and is the hover colour on every link — but
   it is never a field, never a wash, and never more than a few hundred pixels
   at a time. Red anchors the month precisely BY being scarce.

   THE VALUE LADDER. The stated risk with a monochrome winter theme is that it
   collapses into pale-on-pale mush. The defence is a deliberate ten-step
   neutral ramp (--jan-shadow through --jan-rime) with a hard rule: everything
   from --jan-slate up the dark end carries text, everything from --jan-branch
   down the light end is scenery and never carries text. Nothing sits in the
   middle where it could be mistaken for either. Every accent below was measured
   against the page ground #e8eef2, and the WEAKEST of them is 5.69:1 — every
   single one clears WCAG AA body text, not just large text, so the heading
   gradient is safe even on an h6 at 11px where the 3:1 large-text allowance
   does not apply.

   THE COLD LINK ACCENT. --jan-ice is the one cold hue reserved for links, at
   6.06:1 on the ground. Colour alone is not enough here and the numbers say so:
   ice against the body ink measures 2.17:1, well under the 3:1 that would let
   hue carry the distinction on its own. This theme used to underline prose
   links at rest for exactly that reason; the underline is gone now, per the
   standing no-underline rule (2026-08-14). It cost nothing live — main.css's
   link-camouflage.css already holds every link flat at rest sitewide and had
   been winning the cascade over this theme's underline regardless, so no
   reader ever saw it. The unresolved 2.17:1 gap this comment used to answer is
   real and is a link-camouflage-level question (every theme rests with no
   non-colour cue by that sheet's design), not something this theme can fix on
   its own — see public/link-camouflage.css before reopening it.

   PURE CSS. No url(), no image, no webfont, no canvas. Every branch, stalk,
   drift and frost needle below is a gradient, a clip-path or a box-shadow.
   =========================================================================== */

body[data-theme-id="january"] {
  /* ---- The neutral ramp ------------------------------------------------
     Ten steps from near-black to rime. shadow/ink/steel/slate carry text.
     branch/haze/sky/drift are scenery only and are never allowed under a
     glyph. snow/frost/rime are grounds.

     THE CAST IS WARM NOW, AND THE MONTH IS STILL COLD (2026-08-16). This ramp
     used to be pulled a few points toward blue on every step, and the comment
     here argued that the blue cast was what separated "cold" from "grey". It
     was wrong, and the no-blue-light rule made proving it compulsory: what
     reads as cold in this theme is the *structure* — a flat field under four
     fifths of empty sky, a bare bough, dead stalks, and a value range at the
     light end so narrow that nothing has any modelling. None of that is a
     hue. The steps below are the same lightnesses on a warm axis and January
     is no less bleak for it.

     THE TOP THREE ARE RE-CUT, NOT CLAMPED. snow/frost/rime were #e8eef2,
     #f7fafc and #ffffff — L 0.946, 0.983, 1.000. The ceiling (L 0.929) sits
     below all three, so a straight clamp put the page ground, the lit drift
     and the rime highlight on the same value and flattened the field into one
     sheet of paper. They are re-cut as three real steps inside the band the
     ceiling leaves, with sky and drift eased down to make room, and the
     chroma opening slightly toward the light end so the brightest thing on
     screen is also the warmest. Every accent below still clears 4.5:1 on the
     new ground; the weakest is --jan-sun at 5.04. */
  --jan-shadow: #1b1812;
  --jan-ink: #28241d;
  --jan-steel: #534d43;
  --jan-slate: #605b52;
  --jan-branch: #8d877d;
  --jan-haze: #b2ada2;
  --jan-sky: #cfc9c0;
  --jan-drift: #e2dace;
  --jan-snow: #e8dfd0;
  --jan-frost: #ede3d1;
  --jan-rime: #f2e6d2;

  /* ---- The accents -----------------------------------------------------
     Nine hues, every one re-measured against the --jan-snow ground (#e8dfd0)
     on 2026-08-16. The number after each is its contrast ratio there; the
     floor is 4.5:1 and the weakest here is 5.04, so any of them may carry
     body text, a heading stop or a border.
     They are also spread across the wheel rather than bunched: a heading
     gradient built from eight colours that all sit in the same corner reads as
     one smudge no matter how dark it is, which is the failure this set exists
     to avoid. */
  --jan-rose: #a31511;        /* 5.95  winterberry — THE anchor */
  --jan-rose-deep: #780f0e;   /* 8.49  the berry in shadow */
  --jan-plum: #812b2b;        /* 6.87  rose hip gone over */
  --jan-rust: #8a4520;        /* 5.38  dead oak leaf still hanging */
  --jan-sun: #6f5a1c;         /* 5.04  the thin sun, tarnished brass */
  --jan-pine: #3c5d3c;        /* 5.63  the one evergreen on the line */
  --jan-ice: #5e5835;         /* 5.44  the link accent. Was glacier blue;
                                 now the tarnish on the sun, same value */
  --jan-indigo: #593d22;      /* 7.52  the cold hour before dusk */
  --jan-violet: #623a31;      /* 7.33  long winter shadow on snow */

  /* ---- Scene geometry --------------------------------------------------
     The horizon is derived from the field height rather than stated twice, so
     the drift line, the stalks standing on it and the mobile block below can
     never drift out of register. 0.6 is where the clip-path's average top edge
     lands inside the field box. */
  --jan-field: clamp(5rem, 13vh, 8.5rem);
  --jan-horizon: calc(var(--jan-field) * 0.65);
  /* The bough's height is DERIVED from its width rather than stated, so the box
     keeps a fixed 1.53:1 aspect at every viewport. The clip-path below is a set
     of percentages, so a box that changes proportion shears the branch — twigs
     that were drawn at 40 degrees flatten toward horizontal on a wide screen and
     rear up toward vertical on a narrow one. Locking the aspect is what keeps
     the drawing a drawing. */
  --jan-bough-w: min(28rem, 42vw);
  --jan-bough-h: calc(var(--jan-bough-w) * 0.654);

  /* ---- Token map -------------------------------------------------------
     Every --tt-* token resolves to a real measured colour. Nothing is #000 or
     #fff: a placeholder here is what flattens headings, tags and eyebrows into
     one black slab and makes the heading gradient invisible. */
  --tt-bg: var(--jan-snow);
  /* Link-hover paired to THIS block's ground (standing rule 2026-08-14), not
     the mode name — january's unmoded block is day, per the switch commentary
     in main.css. #e8eef2 is light: #FF465A only measures 2.86:1 here, so day
     takes the same-hue dark variant, #BD0014 — 5.65:1. */
  --link-hover: #BC0900;
  --tt-bg-alt: var(--jan-drift);
  --tt-cyan: var(--jan-ink);
  --tt-cyan-soft: var(--jan-steel);
  --tt-yellow: var(--jan-sun);
  --tt-orange: var(--jan-rust);
  /* Bold text is red on every Agoramores month; here that is the berry, and it
     is the single loudest use of the anchor inside running prose. */
  --tt-chartreuse: var(--jan-rose);
  --tt-green: var(--jan-pine);
  --tt-pink: var(--jan-plum);
  --tt-purple: var(--jan-violet);
  --tt-blue: var(--jan-ice);
  --tt-teal: var(--jan-slate);
  --tt-gray: var(--jan-slate);
  --tt-gold: var(--jan-sun);
  --tt-red: var(--jan-rose);
  --tt-breadcrumb-text: var(--jan-rose-deep);
  /* Daylight, and a light ground: a bloom would be a smear. Every text-shadow
     keyed off this token resolves to nothing, which is the intent. */
  --tt-breadcrumb-glow: transparent;
  /* Hover/focus halo for the zodiac glyphs, and the reason --zodiac-glow is a
     separate token from --tt-breadcrumb-glow: that one is transparent here, so
     a chip keyed off it would have no affordance at all. On a near-white card
     a bright halo is invisible, so this month's halo is DARK — the berry's own
     shadow, blooming outward from the glyph. Same inversion the lava-lamp
     sheet needs. Cast from text-shadow on the character and drop-shadow on the
     moon path, so it traces the shape and can never render as a box. Never a
     border; the rule that consumes this lives once, in main.css. */
  --zodiac-glow: rgba(120, 15, 14, 0.5);
  /* The engraving on the tarot card: the one text-shadow that cuts the card's
     numeral and the breadcrumb separators INTO its face rather than printing
     them on it. main.css defaults it to a black lip, which is right under a
     glyph on a dark card and wrong under one on frosted glass — on a pale face
     the lit edge of a struck stroke is the white BELOW the letter, not the
     black. Every light-ground theme has to state this or it inherits a smudge. */
  --tt-engrave: 0 1px 0 rgba(242, 230, 210, 0.75);

  /* ---- Gradients -------------------------------------------------------
     Red leads all three and returns inside the cycle. The structural palette
     (borders, rails, frames) runs rose → rust → pine → ice → indigo → rose, so
     every frame on the page opens and closes on the anchor. */
  --tt-heading-rainbow: linear-gradient(
    90deg,
    var(--jan-rose),
    var(--jan-rust),
    var(--jan-pine),
    var(--jan-ice),
    var(--jan-indigo),
    var(--jan-rose)
  );
  --tt-heading-rainbow-vertical: linear-gradient(
    180deg,
    var(--jan-rose),
    var(--jan-rust),
    var(--jan-pine),
    var(--jan-ice),
    var(--jan-indigo),
    var(--jan-rose)
  );
  /* Two identical eight-stop cycles across the 200% background main.css sets,
     so headingRainbowFlow loops with no visible reset, and the sheet opens and
     closes on rose so the wrap point is seamless too. Rose sits at stops 1 and
     6 of each cycle — red twice per revolution, red-dominant by count. Every
     stop clears 4.5:1 on the ground, which matters because h4/h5/h6 are set
     below 18.66px and get no large-text allowance. */
  --tt-heading-text-rainbow: linear-gradient(
    90deg,
    var(--jan-rose),
    var(--jan-rust),
    var(--jan-sun),
    var(--jan-pine),
    var(--jan-ice),
    var(--jan-rose),
    var(--jan-indigo),
    var(--jan-violet),
    var(--jan-rose),
    var(--jan-rust),
    var(--jan-sun),
    var(--jan-pine),
    var(--jan-ice),
    var(--jan-rose),
    var(--jan-indigo),
    var(--jan-violet),
    var(--jan-rose)
  );

  /* ---- Type ------------------------------------------------------------
     The heading face is a system stack. The project loads no webfont anywhere —
     no @font-face, no @import, no external link — so this costs nothing on the
     wire and the first paint is already the finished typography.

     A neo-grotesque is the point. Helvetica has no calligraphic warmth, no
     humanist stroke modulation and no ornament of any kind; it is the face
     equivalent of a bare field, and it is the reason this month reads austere
     rather than merely pale. It also holds up at 300 weight on a light ground,
     where a high-contrast face would go spindly and a slab would go heavy.

     It is confined to headings now (2026-08-15, user instruction). It had been
     set on --font-sans as well, and the text font is now locked to --font-text
     in main.css and shared by all fourteen themes — which this sheet loses the
     least by, since a neo-grotesque is the WORST of the four displaced body
     faces under defocus: Helvetica's apertures are nearly closed, so c, e, s
     and a collapse into o at the first hint of blur. Austerity survives in the
     heading, the ground and the empty field; it does not need the paragraph.

     --font-mono and --font-cursive are untouched at the token level: the brand
     wordmark is a locked fixture and keeps its own stack. */
  --font-heading: "Helvetica Neue", Helvetica, "Segoe UI", Arial, sans-serif;

  --bg: var(--jan-snow);
  --surface: transparent;
  --text: var(--tt-cyan);
  --text-soft: var(--tt-cyan-soft);
  --muted: var(--tt-gray);
  /* The loud structural frame is the anchor; the quiet hairlines are steel, so
     a table rule or an input edge stays neutral instead of turning the reading
     surface pink. Every frame that is actually SEEN is drawn by the rainbow
     border-image in main.css, which is red-led, so the month still reads red
     at every edge. */
  --border: var(--tt-red);
  --border-dim: rgba(96, 91, 82, 0.34);
  --border-teal: rgba(96, 91, 82, 0.55);
  background: var(--jan-snow);
  color: var(--tt-cyan);
  color-scheme: light;
}

/* ---------------------------------------------------------------------------
   THE PANE. The CRT scanline is a permanent fixture and stays a
   repeating-linear-gradient — it just stops being a cathode artefact and
   becomes the fine crystalline striation on a cold window. Two passes at
   complementary steep angles, the way frost facets cross on real glass.

   Alpha is pinned near the floor on purpose. This layer sits at z-index 5,
   ABOVE the text, so anything it adds is subtracted from every contrast ratio
   on the page. At 0.045/0.03 over a ~20% duty cycle the effective veil is
   under one percent and the measured ratios hold; a corner bloom was drafted
   here and cut, because at the alpha needed to see it the footer's muted text
   dropped from 5.29:1 to 3.89:1. It has to be felt and never read.
   --------------------------------------------------------------------------- */
body[data-theme-id="january"]::before {
  background:
    repeating-linear-gradient(
      96deg,
      rgba(242, 230, 210, 0.045) 0 1px,
      transparent 1px 6px
    ),
    repeating-linear-gradient(
      -84deg,
      rgba(242, 230, 210, 0.03) 0 1px,
      transparent 1px 9px
    );
}

/* ---------------------------------------------------------------------------
   THE SKY. Four fifths of the frame and almost nothing in it, which is the
   whole composition.

   A real January overcast is not a smooth ramp: it is a slightly heavier deck
   overhead thinning toward the horizon, with the light pooling low because
   that is where the cloud is thinnest and where the snow is throwing light back
   up into it. So the gradient runs DARKEST AT THE TOP and brightest just above
   the drift line, which is the opposite of the night skies every other month
   ships and is the single strongest cue that this is daylight.

   The sun is a disc, not a glow: a wan white circle with one soft ring off it,
   set high and right where it barely clears the trees in January and giving no
   warmth to the sky around it. It is deliberately only a step or two brighter
   than the cloud it sits in — a January sun you can look straight at.
   --------------------------------------------------------------------------- */
body[data-theme-id="january"] .night-sky {
  background:
    /* the thin sun and its one halo ring */
    radial-gradient(circle 2.6rem at 76% 15%, rgba(242, 230, 210, 0.92) 0 42%, rgba(242, 230, 210, 0.26) 62%, transparent 78%),
    radial-gradient(circle 7.5rem at 76% 15%, rgba(242, 230, 210, 0.3), transparent 72%),
    /* light pooling off the snow, low and wide */
    radial-gradient(ellipse 90% 34% at 50% 104%, rgba(242, 230, 210, 0.72), transparent 76%),
    /* the far bank of haze that swallows the treeline. Stops are spread wide
       and start at half height on purpose: a tighter band leaves a visible
       horizontal seam across the middle of an otherwise empty sky, which is the
       one artefact a composition this bare cannot hide. */
    linear-gradient(180deg, transparent 0 52%, rgba(178, 173, 162, 0.2) 74%, rgba(178, 173, 162, 0.07) 90%, transparent 100%),
    /* The deck thins downward, but the LAST stops stay cool rather than running
       to white. The snow field below is near-white, and if the sky reaches the
       same value at the horizon the drift line disappears — a real whiteout,
       accurate and useless. Holding the sky two steps darker is what lets the
       field read as ground. */
    linear-gradient(
      180deg,
      #c2bdb3 0%,
      #c9c4bb 16%,
      #d0cdc4 34%,
      #d9d6cf 54%,
      #e5ded1 72%,
      #ebe4d7 88%,
      #f2e6d2 100%
    );
  background-repeat: no-repeat;
}

/* ---------------------------------------------------------------------------
   THE TREELINE. A band standing on the drift line: dead stalks and the fine
   scrub of a distant leafless thicket.

   NOT repeating-linear-gradient. That was the first attempt and it was wrong:
   a repeating gradient puts every stalk at an identical interval, and what came
   out was a barcode — perfectly even, unmistakably machine-made, and the single
   most artificial thing on the page. Nothing in a field is evenly spaced.

   Each pass is instead ONE plain linear-gradient carrying several hand-placed
   hairlines at irregular offsets, tiled at a wide odd period (173 / 127 / 89 /
   37px). The eye reads the irregularity inside a tile long before it notices
   the tile repeating, and the four periods share no factor, so the four passes
   never phase into alignment either. Two passes are also drawn a few degrees
   off vertical — 96deg and 84deg — so a share of the stalks lean, in both
   directions, the way dead stalks actually stand.

   Height and alpha both fall off with distance: the tallest pass is the nearest
   and darkest, the shortest is the far thicket dissolving into the haze. That
   is atmospheric perspective done with two numbers per layer.

   No z-index. That is load bearing: with z-index auto this pseudo-element
   paints beneath .night-sky__stars (z1) and .night-sky__aurora (z2), so the
   blowing snow passes IN FRONT of the stalks and the snow field BURIES their
   bases. Both are what actually happens, and both come free from the paint
   order rather than from another element.
   --------------------------------------------------------------------------- */
body[data-theme-id="january"] .night-sky::before {
  inset: auto 0 calc(var(--jan-horizon) - 0.45rem) 0;
  height: clamp(1.5rem, 3.6vh, 2.6rem);
  opacity: 1;
  background-image:
    /* near stalks — sparsest, tallest, darkest, dead upright */
    linear-gradient(
      90deg,
      transparent 0 11px,
      rgba(103, 97, 87, 0.54) 11px 12.4px,
      transparent 12.4px 43px,
      rgba(103, 97, 87, 0.46) 43px 44.2px,
      transparent 44.2px 78px,
      rgba(103, 97, 87, 0.5) 78px 79.5px,
      transparent 79.5px 121px,
      rgba(103, 97, 87, 0.4) 121px 122.1px,
      transparent 122.1px 152px,
      rgba(103, 97, 87, 0.48) 152px 153.3px,
      transparent 153.3px
    ),
    /* mid scrub, leaning one way */
    linear-gradient(
      96deg,
      transparent 0 9px,
      rgba(132, 126, 115, 0.42) 9px 10.1px,
      transparent 10.1px 37px,
      rgba(132, 126, 115, 0.38) 37px 38px,
      transparent 38px 66px,
      rgba(132, 126, 115, 0.44) 66px 67.2px,
      transparent 67.2px 94px,
      rgba(132, 126, 115, 0.36) 94px 95px,
      transparent 95px 113px,
      rgba(132, 126, 115, 0.4) 113px 114.1px,
      transparent 114.1px
    ),
    /* mid scrub, leaning the other */
    linear-gradient(
      84deg,
      transparent 0 6px,
      rgba(152, 147, 136, 0.36) 6px 7px,
      transparent 7px 29px,
      rgba(152, 147, 136, 0.32) 29px 29.9px,
      transparent 29.9px 51px,
      rgba(152, 147, 136, 0.38) 51px 52.1px,
      transparent 52.1px 74px,
      rgba(152, 147, 136, 0.3) 74px 74.9px,
      transparent 74.9px
    ),
    /* far thicket — dense, short, nearly gone into the haze */
    linear-gradient(
      90deg,
      transparent 0 4px,
      rgba(170, 165, 155, 0.28) 4px 4.8px,
      transparent 4.8px 15px,
      rgba(170, 165, 155, 0.24) 15px 15.7px,
      transparent 15.7px 27px,
      rgba(170, 165, 155, 0.26) 27px 27.8px,
      transparent 27.8px
    );
  background-size: 173px 100%, 127px 68%, 89px 46%, 37px 26%;
  background-position: left bottom, 23px bottom, 61px bottom, 7px bottom;
  background-repeat: repeat-x;
  animation: none;
  transform: none;
}

/* ---------------------------------------------------------------------------
   THE BOUGH. One bare branch overhanging the top-right corner — the theme's
   only real illustration and the only place a viewer's eye has anywhere to go
   before the horizon.

   Drawn as a single clip-path polygon on a gradient-filled box, which is the
   same technique main.css uses for July's skyline. The polygon traces the whole
   silhouette in one closed loop: it walks the limb's top edge from the right
   edge leftward, detouring up-and-back into each of the five twigs that point
   upward, reaches the tip, then walks the bottom edge back rightward, detouring
   down-and-back into the five that point downward. Every detour returns to the
   main edge slightly PAST where it left, in the direction of travel, which is
   what keeps the loop simple and non-self-intersecting. Thickness tapers from
   about 6% of the box at the base to under 1% at the tip.

   WHAT MAKES IT A BRANCH AND NOT AN AIRCRAFT. The first draft had four long
   twigs at similar shallow angles hung off a straight taper, and it read
   unmistakably as a swept-wing jet. Three things fixed it, and all three are
   worth keeping if this is ever redrawn: the limb is a twelve-segment ARC and
   is nowhere straight; the ten twigs are at ten different angles between 26 and
   72 degrees with four different lengths, two of them stubs; and the forks sit
   at irregular intervals instead of evenly down the limb. Regularity is what
   made it read as manufactured.

   The twig geometry was generated from a limb centreline plus an angle-and-
   length table rather than hand-traced, which is why the numbers below are not
   round. Angles were computed against the box's real 1.53:1 pixel aspect, so
   they are true degrees on screen and not degrees in percentage space — which
   is also why --jan-bough-h is derived from --jan-bough-w above and never set
   independently.

   The fill is a gradient rather than a flat silhouette, for two reasons. It is
   true — bare wood against a bright overcast halates and washes out toward the
   fine ends — and it is defensive: the thick end sits hard in the top-right
   corner where nothing but empty header sits, and the pale end is the part that
   reaches inward toward where a narrow viewport might put text. Body ink over
   the DARKEST point of the bough still measures 4.5:1, so even the worst
   overlap stays readable.

   Placed on .night-sky::after, which main.css does not use. z-index auto puts
   it behind the blowing snow, so flakes cross in front of the branch.
   --------------------------------------------------------------------------- */
body[data-theme-id="january"] .night-sky::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  width: var(--jan-bough-w);
  height: var(--jan-bough-h);
  pointer-events: none;
  background: linear-gradient(252deg, #7c7569 0%, #8d877d 46%, #9e9990 74%, #ada9a0 100%);
  clip-path: polygon(
    /* --- top edge, right → left, detouring up into each upward twig --- */
    102% -1.35%,
    95.8% 0.56%,
    86.78% -7.7%,
    86.65% -7.49%,
    94.2% 1.06%,
    92% 1.73%,
    83% 5.34%,
    79.72% 6.87%,
    64.87% -3.66%,
    64.77% -3.41%,
    78.28% 7.54%,
    74% 9.52%,
    65% 14.47%,
    60.6% 17.27%,
    56.78% 6.6%,
    56.6% 6.71%,
    59.4% 18.04%,
    56% 20.19%,
    47% 26.68%,
    41.5% 31.12%,
    28.25% 22.79%,
    28.17% 23.06%,
    40.5% 31.93%,
    38% 33.94%,
    30% 41.33%,
    25.4% 45.8%,
    17% 32.45%,
    16.85% 32.64%,
    24.6% 46.58%,
    22% 49.1%,
    15% 56.21%,
    9% 62.47%,
    /* --- the tip --- */
    4% 67.9%,
    4% 68.5%,
    /* --- bottom edge, left → right, detouring down into each downward twig --- */
    9% 63.13%,
    15% 56.99%,
    16.66% 55.36%,
    9.07% 63.92%,
    8.96% 63.69%,
    17.34% 54.69%,
    22% 50.1%,
    30% 42.67%,
    32.55% 40.43%,
    30.59% 50.47%,
    30.4% 50.38%,
    33.45% 39.64%,
    38% 35.66%,
    47% 28.92%,
    51.44% 26%,
    39.89% 42.44%,
    39.76% 42.23%,
    52.56% 25.26%,
    56% 23.01%,
    65% 17.93%,
    70.34% 15.4%,
    63.74% 31.17%,
    63.58% 31.01%,
    71.66% 14.78%,
    74% 13.68%,
    83% 10.26%,
    87.25% 8.94%,
    85.22% 15.07%,
    85.05% 14.95%,
    88.75% 8.47%,
    92% 7.47%,
    102% 5.35%
  );
}

/* ---------------------------------------------------------------------------
   THE WEATHER. Two depths, and both of them are wind rather than snowfall.

   A blizzard would be busy and a gentle vertical drift would be pretty; January
   here is neither. What is in the air is a thin veil of fine snow being carried
   sideways and a ground blizzard skating across the drifts — the two things
   that are actually moving in a barren field in February-cold weather, and the
   two that read as WIND, which is the sensation the month is after.

   Both layers are GREY, not white. This is the counter-intuitive part and it
   is correct: snow silhouetted against a bright overcast sky is darker than the
   sky behind it, so white flakes on this ground would be literally invisible.
   The values are pulled from --jan-haze and its neighbours.

   Seamlessness. The veil translates diagonally, so EVERY gradient layer in it
   shares one tile size (26rem × 20rem) and the layer travels exactly that tile
   per loop — density comes from five flakes placed at different points inside
   the one tile rather than from five different tile sizes. The spindrift
   travels horizontally only, so there its tile WIDTHS must match (12rem) but
   the heights are free to differ, which is what stops the streaks from lining
   up into rows. Transform only: no filter, no background-position animation, no
   layout property.
   --------------------------------------------------------------------------- */

/* The high veil: fine, sparse, very slow. Roughly eight pixels a second across
   the screen — it should take a moment to notice that anything is moving. The
   box is oversized up and right because the layer travels down and left; those
   are the two edges that would otherwise open a gap. */
body[data-theme-id="january"] .night-sky__stars--far {
  inset: -22rem -28rem -2rem -2rem;
  opacity: 0.5;
  background-image:
    radial-gradient(circle at 12% 18%, rgba(159, 153, 142, 0.78) 0 1.1px, transparent 1.9px),
    radial-gradient(circle at 63% 41%, rgba(168, 163, 153, 0.66) 0 0.9px, transparent 1.6px),
    radial-gradient(circle at 34% 72%, rgba(159, 153, 142, 0.6) 0 1px, transparent 1.7px),
    radial-gradient(circle at 84% 88%, rgba(178, 173, 162, 0.54) 0 0.8px, transparent 1.5px),
    radial-gradient(circle at 47% 6%, rgba(168, 163, 153, 0.48) 0 0.7px, transparent 1.4px);
  background-size: 26rem 20rem;
  background-position: 0 0, 6rem 3rem, 13rem 8rem, 3rem 14rem, 19rem 11rem;
  background-repeat: repeat;
  animation: januarySnowVeil 58s linear infinite;
}

/* Ground blizzard: the band just above the drift line, horizontal, and six
   times the speed of the veil. Blown snow does not fall, it skates.

   The streaks are SHORT. The first pass used ellipses up to 7.5rem long at 0.44
   opacity and they read as scratches ruled across the middle of the page —
   long, straight, perfectly parallel marks look like a damaged screen, not like
   weather. Capping every streak under 2.2rem, dropping the band to start at 74%
   so it sits below the reading column, and pulling the opacity to 0.3 turns the
   same layer into granular snow being pushed along the ground.

   The five tile HEIGHTS are deliberately unrelated so no two rows of streaks
   ever run together; only the WIDTHS have to agree, at 12rem, because the
   travel is on one axis. */
body[data-theme-id="january"] .night-sky__stars--near {
  inset: 74% -14rem -3rem -3rem;
  opacity: 0.3;
  background-image:
    radial-gradient(ellipse 1.6rem 0.075rem at 22% 26%, rgba(155, 149, 136, 0.62) 0 42%, transparent 100%),
    radial-gradient(ellipse 1.1rem 0.065rem at 68% 54%, rgba(166, 161, 149, 0.54) 0 42%, transparent 100%),
    radial-gradient(ellipse 2.2rem 0.06rem at 41% 79%, rgba(177, 172, 161, 0.5) 0 42%, transparent 100%),
    radial-gradient(ellipse 0.9rem 0.08rem at 87% 12%, rgba(155, 149, 136, 0.56) 0 42%, transparent 100%),
    radial-gradient(ellipse 1.4rem 0.07rem at 9% 62%, rgba(166, 161, 149, 0.5) 0 42%, transparent 100%);
  background-size: 12rem 4rem, 12rem 5.5rem, 12rem 7.5rem, 12rem 9.5rem, 12rem 6.5rem;
  background-position: 0 0, 3rem 1.5rem, 7rem 3rem, 1rem 5rem, 9rem 2.5rem;
  background-repeat: repeat;
  animation: januarySpindrift 5.5s linear infinite;
}

/* ---------------------------------------------------------------------------
   THE FIELD. The month's ground element, in the slot July uses for its city
   skyline — which is Fourth-of-July scenery and belongs to July alone. Here it
   is old drifted snow under a low, nearly flat horizon.

   The drift line is a clip-path with eighteen points across the top edge,
   oscillating between 28% and 42% of the box. That is a very shallow wave on
   purpose: the brief is a LOW FLAT horizon, and the moment the amplitude goes
   past about 15% it stops reading as wind-packed snow and starts reading as
   hills. Straight segments between closely spaced points are indistinguishable
   from a curve at this scale, which is why polygon() is enough and no smoothing
   is needed.

   The fill runs bright at the crest and cools toward the viewer, because the
   crest is catching what light there is and the near field is in its own
   shadow. Two soft ellipses cut the hollows between drifts. The footer sits on
   this surface, and its muted type measures 5.80:1 against the brightest part
   of it.
   --------------------------------------------------------------------------- */
body[data-theme-id="january"] .night-sky__aurora {
  display: block;
  z-index: 2;
  left: 0;
  right: 0;
  top: auto;
  bottom: -1px;
  inset-block-start: auto;
  height: var(--jan-field);
  box-shadow: none;
  background:
    /* hollows and wind-scour between the drifts */
    radial-gradient(ellipse 22rem 2.4rem at 24% 104%, rgba(138, 130, 116, 0.22), transparent 72%),
    radial-gradient(ellipse 16rem 1.8rem at 68% 108%, rgba(138, 130, 116, 0.18), transparent 70%),
    /* The blue shadow immediately under the crest, where the drift undercuts.
       This band is what makes the horizon a LINE rather than a soft fade — a
       white field meeting a pale sky with nothing between them reads as an
       unfinished gradient. It runs cool and fairly strong for three percent of
       the field, then releases. */
    linear-gradient(180deg, transparent 0 3%, rgba(167, 158, 142, 0.34) 9%, rgba(185, 178, 164, 0.14) 20%, transparent 38%),
    linear-gradient(180deg, #f2e6d2 0%, #f2e6d2 22%, #f2e6d2 58%, #ede6d9 100%);
  background-repeat: no-repeat;
  clip-path: polygon(
    0 42%,
    5% 39%,
    11% 35%,
    17% 32%,
    23% 33%,
    29% 37%,
    35% 39%,
    41% 36%,
    47% 31%,
    53% 28%,
    59% 30%,
    65% 34%,
    71% 36%,
    77% 33%,
    83% 29%,
    89% 31%,
    95% 36%,
    100% 39%,
    100% 100%,
    0 100%
  );
}

/* Fireworks are Independence Day furniture: July theme only. The JS also refuses
   to spawn them off-July, so this is belt-and-braces for any burst already on
   screen when the theme is switched. */
body[data-theme-id="january"] .night-sky__fireworks {
  display: none;
}

/* ---------------------------------------------------------------------------
   THE CARD — the breadcrumb bar, which is the one element in the whole project
   allowed its own background. That makes it the only place a real piece of
   craft can be built, so this month spends its hoarfrost here rather than
   smearing it over the viewport where it would eat contrast from every line of
   text on the page.

   It is a pane of cold glass with rime creeping in from all four edges. Each
   needle pass is a repeating-linear-gradient of two stops, not one: a pure
   white hairline immediately followed by a thin blue-grey shadow. That pairing
   is the entire trick — a single white line on white glass is invisible, but a
   white line with a shadow beside it reads as a raised crystal with a light
   source. The four edges use four different periods (6/8/9/11px) so opposite
   edges never mirror each other, and two scattered dot passes put frost
   crystals out across the middle of the pane.

   Static. Nothing here animates; the existing sweep on ::before is the card's
   only motion and it is not new.
   --------------------------------------------------------------------------- */
body[data-theme-id="january"] .breadcrumb-nav {
  background:
    /* rime along the top edge */
    repeating-linear-gradient(
      90deg,
      rgba(242, 230, 210, 0.95) 0 1px,
      rgba(175, 168, 154, 0.3) 1px 1.8px,
      transparent 1.8px 6px
    ) left top / 100% 0.55rem repeat-x,
    /* rime along the foot */
    repeating-linear-gradient(
      90deg,
      rgba(242, 230, 210, 0.9) 0 1px,
      rgba(175, 168, 154, 0.26) 1px 1.7px,
      transparent 1.7px 9px
    ) left bottom / 100% 0.42rem repeat-x,
    /* rime up the left and right stiles */
    repeating-linear-gradient(
      0deg,
      rgba(242, 230, 210, 0.9) 0 1px,
      rgba(175, 168, 154, 0.26) 1px 1.7px,
      transparent 1.7px 8px
    ) left top / 0.42rem 100% repeat-y,
    repeating-linear-gradient(
      0deg,
      rgba(242, 230, 210, 0.88) 0 1px,
      rgba(175, 168, 154, 0.24) 1px 1.6px,
      transparent 1.6px 11px
    ) right top / 0.36rem 100% repeat-y,
    /* crystals scattered out across the pane — two tile sizes with no common
       factor, so they never grid up over the instruments */
    radial-gradient(circle at 30% 40%, rgba(242, 230, 210, 0.8) 0 0.8px, transparent 1.5px)
      0 0 / 19px 15px repeat,
    radial-gradient(circle at 70% 65%, rgba(184, 178, 164, 0.34) 0 0.7px, transparent 1.4px)
      7px 5px / 27px 23px repeat,
    /* the glass itself, lit from above */
    linear-gradient(
      180deg,
      rgba(242, 230, 210, 0.88) 0%,
      rgba(242, 230, 210, 0.8) 44%,
      rgba(242, 230, 210, 0.76) 100%
    );
  box-shadow:
    inset 0 1px 0 rgba(242, 230, 210, 0.95),
    inset 0 -1px 0 rgba(145, 139, 126, 0.2),
    0 1px 3px rgba(48, 43, 33, 0.07);
}

/* The existing sweep becomes a pass of pale winter light travelling across the
   frosted pane. Same element, same keyframe, same duration — only the colour
   moves off July's cyan and hotpink. */
body[data-theme-id="january"] .breadcrumb-nav::before {
  background: linear-gradient(
    90deg,
    transparent,
    rgba(242, 230, 210, 0.62),
    rgba(230, 227, 217, 0.4),
    transparent
  );
}

/* The brand in bare black ink on a white field, lifted by a single-pixel rime
   highlight underneath — letters cut into frost rather than lit from behind.
   It goes winterberry on hover, which is the anchor doing what the anchor does
   here: marking the one thing that is alive. */
body[data-theme-id="january"] .brand a {
  color: var(--jan-ink);
  text-shadow: 0 1px 0 rgba(242, 230, 210, 0.92);
}

body[data-theme-id="january"] .brand a:hover {
  color: var(--jan-rose);
  text-shadow: 0 1px 0 rgba(242, 230, 210, 0.92);
}

/* ---------------------------------------------------------------------------
   HEADINGS.

   Set the way a cold empty page wants to be set: light weight, wide tracking,
   no ornament, and a hairline horizon rule under every H2. The tracking is the
   whole idea — letterspacing is negative space, and this is a theme about
   negative space.

   The glow goes. main.css casts a cyan bloom on every heading, which is July's
   colour and would be a smear on a light ground in daylight. What replaces it
   is a zero-blur white drop-shadow one pixel down — type cut into ice.

   It has to be a FILTER and not a text-shadow. These headings are painted with
   background-clip: text and a transparent fill, so a text-shadow renders
   through the transparent glyph and buries the gradient under a flat slab.
   drop-shadow() reads the composited alpha instead and lands behind the
   letters, which is the same reason October uses it.

   The trigger selectors are stated alongside the bare elements because
   main.css sizes and paints those at (0,2,0) and (0,3,0), which would outrank
   a plain `main h2` here. */
body[data-theme-id="january"] main h1,
body[data-theme-id="january"] .page-title,
body[data-theme-id="january"] main h2,
body[data-theme-id="january"] main h3,
body[data-theme-id="january"] main h4,
body[data-theme-id="january"] main h5,
body[data-theme-id="january"] main h6,
body[data-theme-id="january"] .markdown-page .heading-section__trigger {
  font-family: var(--font-heading);
  font-style: normal;
  text-shadow: none;
  /* `var(--heading-tint)` first: it is the site-wide per-level heading ladder
     from main.css, and `filter` replaces rather than accumulates, so a rule
     that omits it drops the ladder for this whole sheet. */
  filter: var(--heading-tint) drop-shadow(0 1px 0 rgba(242, 230, 210, 0.85));
}

/* H1 loses the cursive italic. A script face is a warm, handwritten, personal
   thing and this month is none of those; the wordmark in the header keeps it,
   markdown H1 does not. Light weight, a touch of tracking, sentence case —
   uppercase was drafted and cut because real page titles wrap to three lines
   under it. The size comes down because a grotesque sets considerably wider
   than the script it replaces. */
body[data-theme-id="january"] main h1,
body[data-theme-id="january"] .page-title,
body[data-theme-id="january"] .heading-section--level-1 > .heading-section__summary > .heading-section__trigger {
  font-weight: 300;
  font-size: clamp(2.2rem, 6vw, 4rem);
  letter-spacing: 0.005em;
}

/* H2 and H3 are the field markers: uppercase, tracked wide, small. Weight stays
   at 400 rather than dropping to 300 with H1 — at these sizes a 300-weight
   uppercase letterform is too thin for the heading gradient to actually show
   inside it, which is the same trap that made a previous month's headings read
   as flat blocks. */
body[data-theme-id="january"] main h2,
body[data-theme-id="january"] main h3 {
  font-weight: 400;
  text-transform: uppercase;
}

body[data-theme-id="january"] main h2,
body[data-theme-id="january"] .heading-section--level-2 > .heading-section__summary > .heading-section__trigger {
  font-size: clamp(1.15rem, 2.5vw, 1.7rem);
  letter-spacing: 0.2em;
}

body[data-theme-id="january"] main h3,
body[data-theme-id="january"] .heading-section--level-3 > .heading-section__summary > .heading-section__trigger {
  font-size: clamp(0.95rem, 1.7vw, 1.16rem);
  letter-spacing: 0.16em;
}

/* The horizon rule. Every H2 sits over a full-width hairline — the typographic
   echo of the drift line at the foot of the page, and the one place the
   structural rainbow shows up inside running content. Drawn in
   --tt-heading-rainbow so it can never drift off the shared border palette.

   The trigger is a real <h2> (the renderer emits <h2 class="heading-section__
   trigger"> inside the summary), so this reaches both wrapped and bare
   headings with one selector. */
body[data-theme-id="january"] main h2::after {
  content: "";
  display: block;
  width: 100%;
  height: 1px;
  margin-top: 0.55rem;
  background: var(--tt-heading-rainbow);
  opacity: 0.55;
}

/* The section rail keeps its rainbow and loses July's cyan filament glow. */
body[data-theme-id="january"] .heading-section::before {
  box-shadow: none;
}

body[data-theme-id="january"] .page-toc .page-toc__title {
  letter-spacing: 0.2em;
}

/* The eyebrow is the coldest piece of type on the page: rust caps, tracked out
   until it is barely a word any more. */
body[data-theme-id="january"] .eyebrow {
  letter-spacing: 0.34em;
}

/* ---------------------------------------------------------------------------
   LINKS. The one cold accent, and the one place this theme has to work harder
   than a dark one.

   --jan-ice measures 6.06:1 against the ground, comfortably readable. Against
   the BODY INK, though, it measures 2.17:1 — under the 3:1 that would let hue
   alone distinguish a link from the sentence around it. Prose links used to be
   underlined at rest to answer that gap; the underline is gone per the standing
   no-underline rule (2026-08-14). No live behaviour changes: link-camouflage.css
   holds every link flat at rest sitewide and already won that fight in the
   cascade, so the underline never rendered. See public/link-camouflage.css for
   the sitewide rest-state contract before adding a new non-colour cue here.

   Hover and focus go to the anchor red, and both the hotpink text-shadow and
   the looping linkHotpinkGlow keyframe from main.css are cancelled: daylight
   has no neon, and a continuous animation on hover is not something this
   project's motion budget spends on links. The colour swing off body ink is
   the hover signal now that no rule is drawn under the word. */
body[data-theme-id="january"] main a {
  color: var(--jan-ice);
}

/* Hover colour is --link-hover, standing user rule 2026-08-14: #FF465A on
   every theme, not the anchor red --jan-rose any more. Locked in main.css's
   :root; see the contrast note in DUH/rules/presentation.md before assuming
   it clears this ground. */
body[data-theme-id="january"] a:hover,
body[data-theme-id="january"] a:focus-visible {
  color: var(--link-hover);
  text-decoration: none;
  text-shadow: none;
  animation: none;
}

/* Visited prose links cool off into the long-shadow violet — still 8.40:1, so a
   read link is quieter but never harder to read. The zodiac chips are held
   clear of this by the doubled .celestial-chip.celestial-chip:visited rule in
   main.css, which is (0,3,0) against this selector's (0,2,2). */
body[data-theme-id="january"] a:visited {
  color: var(--jan-violet);
  text-shadow: none;
}

/* Keyboard focus. main.css draws a 1px ring in --tt-yellow, which on this month
   is a dark bronze — legible, but a single hairline is thin on a bright ground.
   Two pixels of body ink is 13.13:1 against the page and unmistakable at a
   glance, which is what a focus indicator is for.

   The zodiac chips are NOT reached by this and must not be: their focus
   indicator is the glyph halo, never a ring. `a:focus-visible` here is (0,2,2)
   and `button:focus-visible` is (0,2,1), both under the (0,3,0) of
   .celestial-chip.celestial-chip:focus-visible in main.css. The explicit pin
   further down is the belt to that braces. */
body[data-theme-id="january"] a:focus-visible,
body[data-theme-id="january"] button:focus-visible,
body[data-theme-id="january"] input:focus-visible,
body[data-theme-id="january"] textarea:focus-visible,
body[data-theme-id="january"] select:focus-visible {
  outline: 2px solid var(--jan-ink);
  outline-offset: 3px;
}

/* ---------------------------------------------------------------------------
   SURFACES. Everything below already had a fill or a frame in main.css; each
   one is retuned for a light ground. Nothing gains a background it did not
   already have — there is one shared site background and this month does not
   add a second.
   --------------------------------------------------------------------------- */

/* Inset panels read as cleared ice: brighter than the page, with a cold hairline
   under the top edge so the panel sits DOWN into the surface rather than
   floating on it. `code` gets the fill but not the lip — an inline box
   fragments across line breaks and a hairline would break with it.

   The colour override is not optional here: main.css hardcodes `color: #eceff4`
   on `code`, which is invisible on a white panel. */
body[data-theme-id="january"] input,
body[data-theme-id="january"] textarea,
body[data-theme-id="january"] select,
body[data-theme-id="january"] code,
body[data-theme-id="january"] pre {
  background: rgba(242, 230, 210, 0.72);
  color: var(--jan-ink);
}

body[data-theme-id="january"] input,
body[data-theme-id="january"] textarea,
body[data-theme-id="january"] select,
body[data-theme-id="january"] pre {
  box-shadow: inset 0 1px 0 rgba(145, 139, 126, 0.18);
}

/* A code block is one pane, not one per line: the fill belongs to the <pre> and
   the <code> inside it stays clear. Stated explicitly because the surface rule
   above outranks main.css's `pre code`. */
body[data-theme-id="january"] pre code {
  background: transparent;
  box-shadow: none;
}

/* The table header is the month's biggest single field of red, and it is still
   only a bar a few lines tall. Rime type on winterberry, 7.52:1. */
body[data-theme-id="january"] th {
  background: var(--jan-rose);
  color: var(--jan-frost);
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* Highlighted text takes a winterberry wash rather than a yellow one — the
   anchor again, and the ink over it still measures better than 9:1. */
body[data-theme-id="january"] mark {
  background: rgba(163, 21, 17, 0.1);
  color: var(--jan-rose-deep);
  text-shadow: none;
}

/* No left rule on quotes — border-left is reserved for anchors inside ul/ol and
   is used nowhere in this file. The inset wash just moves from July's green to
   a cold slate, which reads as the shadow a raised block casts on snow. */
body[data-theme-id="january"] blockquote {
  color: var(--jan-steel);
  box-shadow: inset 1rem 0 1.4rem -1.2rem rgba(96, 91, 82, 0.55);
}

body[data-theme-id="january"] .tag {
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* Cards get a hairline of rime along the top edge and the faintest cold shadow
   beneath, replacing July's purple bloom. On a light ground a glow does nothing
   and a shadow does everything. */
body[data-theme-id="january"] .hero-card,
body[data-theme-id="january"] .folder-section {
  box-shadow:
    inset 0 1px 0 rgba(242, 230, 210, 0.9),
    0 1px 3px rgba(48, 43, 33, 0.06);
}

body[data-theme-id="january"] .hero-card:hover,
body[data-theme-id="january"] .folder-section:hover {
  box-shadow:
    inset 0 1px 0 rgba(242, 230, 210, 0.95),
    0 3px 10px rgba(48, 43, 33, 0.1);
}

/* Chrome selected by CLASS, never by element. `button` once reached the moon
   chip, which was a <button> while the seven signs were anchors — one element
   selector here and half the strip drifted away from the other half. The moon
   links to the lunar calendar now and all eight are anchors, which retires the
   symptom, not the rule. Same reason September lists these by class. */
body[data-theme-id="january"] .time-bar,
body[data-theme-id="january"] .sitemap-link,
body[data-theme-id="january"] .calendar-app__nav,
body[data-theme-id="january"] .calendar-app__today {
  background: rgba(242, 230, 210, 0.6);
  box-shadow: inset 0 1px 0 rgba(242, 230, 210, 0.9);
}

body[data-theme-id="january"] .time-bar {
  letter-spacing: 0.16em;
}

/* The footer sits ON the snow field — .night-sky is fixed, so the field is
   always at the foot of the viewport and a short page lands the footer right on
   it, among the stalks. The muted slate measures 5.15:1 there against 5.29:1 on
   the page ground, which still passes, but the stalk hairlines cross the line of
   type; stepping up to the body ink's neighbour puts it at 7.77:1 and the
   crossing stops being noticeable. */
body[data-theme-id="january"] footer {
  color: var(--jan-steel);
}

body[data-theme-id="january"] .sitemap-link:hover,
body[data-theme-id="january"] .calendar-app__nav:hover,
body[data-theme-id="january"] .calendar-app__today:hover,
body[data-theme-id="january"] .sitemap-link:focus-visible,
body[data-theme-id="january"] .calendar-app__nav:focus-visible,
body[data-theme-id="january"] .calendar-app__today:focus-visible {
  background: rgba(242, 230, 210, 0.9);
  color: var(--jan-rose);
  box-shadow:
    inset 0 1px 0 rgba(242, 230, 210, 0.95),
    0 2px 6px rgba(48, 43, 33, 0.1);
}

/* ---------------------------------------------------------------------------
   THE ZODIAC CHIPS CARRY NO FRAME. Belt-and-braces, per the permanent note on
   .celestial-chip in main.css.

   No border, no border-image, no outline ring, no box-shadow — a box-shadow on
   a chip IS a border, because it paints the element's bounding rectangle and
   tightens into a visible rounded box the moment its alpha climbs. Their entire
   hover and focus affordance is the halo cast from --zodiac-glow above, drawn
   on the GLYPH by text-shadow and on the moon by drop-shadow, both of which
   trace the rendered shape and cannot produce a rectangle.

   This pin exists so that nothing added to this sheet later can reach the strip
   by accident. The frame in the breadcrumb bar belongs to the card, never to
   the individual chips.

   `transform` is deliberately NOT restated. This month's chrome is not flat —
   the chips lift like every other month's, and nothing in this sheet sets a
   bare `button` or `a` rule that would cancel it. */
body[data-theme-id="january"] .celestial-chip,
body[data-theme-id="january"] .celestial-chip:hover,
body[data-theme-id="january"] .celestial-chip:focus-visible {
  border: 0;
  box-shadow: none;
  outline: none;
}

/* The astrolabe's engraved rings and the moon's limb are artwork inside the
   illustration, not frames around an element, and they stay. The dial face just
   takes a brighter fill so the brass engraving reads on the frosted card. */
body[data-theme-id="january"] .zodiac-clock .zc-face {
  fill: var(--jan-rime);
  fill-opacity: 0.55;
}

/* The tooltip is a chip of clear ice: a bright pane, the month's own rainbow
   edge from main.css left untouched, and a soft cold shadow instead of the
   heavy black one, which is far too hard against a light ground. */
body[data-theme-id="january"] .celestial-tooltip {
  background: rgba(242, 230, 210, 0.97);
  box-shadow: 0 4px 18px rgba(48, 43, 33, 0.18);
}

/* No list marker at all now, so there is no halo left to strip for daylight. */

/* The scrollbar is the last piece of trim: a steel rail on a clear track, going
   to ink under the pointer. */
body[data-theme-id="january"]::-webkit-scrollbar-thumb,
body[data-theme-id="january"] ::-webkit-scrollbar-thumb {
  background-image: linear-gradient(
    90deg,
    rgba(242, 230, 210, 0.4) 0%,
    rgba(242, 230, 210, 0) 46%,
    rgba(48, 43, 33, 0.14) 100%
  );
}

/* ---------------------------------------------------------------------------
   CALENDAR. main.css hardcodes a warm yellow rgba for today's cell and for the
   event-link hover, which on a cold light theme is the one place the palette
   visibly leaks. Today becomes the winterberry mark instead — the anchor doing
   structural work — and the event hover follows it.
   --------------------------------------------------------------------------- */
body[data-theme-id="january"] .calendar-day--today {
  background: rgba(163, 21, 17, 0.06);
  box-shadow: inset 0 0 0 1px var(--jan-rose);
}

body[data-theme-id="january"] .calendar-day--today .calendar-day__number {
  color: var(--jan-rose-deep);
}

body[data-theme-id="january"] .calendar-event__link:hover,
body[data-theme-id="january"] .calendar-event__link:focus-visible {
  color: var(--jan-rose-deep);
  background: rgba(163, 21, 17, 0.08);
}

body[data-theme-id="january"] .calendar-subscribe__action:hover,
body[data-theme-id="january"] .calendar-subscribe__action:focus-visible {
  color: var(--jan-rose-deep);
  background: rgba(163, 21, 17, 0.08);
}

body[data-theme-id="january"] .calendar-subscribe {
  background: rgba(242, 230, 210, 0.55);
}

/* ---------------------------------------------------------------------------
   RESPONSIVE. Everything that is sized in absolute scene units scales together
   from the four geometry variables at the top, so the horizon, the stalks
   standing on it and the field under it stay in register at any width.

   The bough comes down hardest. At desktop it occupies dead space in the
   top-right; at phone width the header stacks and that space is no longer dead,
   so the branch is pulled back to a corner accent. The wide heading tracking
   also comes in — 0.2em on a 1.15rem uppercase H2 is elegant on a laptop and
   wraps every second heading on a 360px screen.
   --------------------------------------------------------------------------- */
@media (max-width: 800px) {
  /* Only the WIDTH is restated. The height follows from it, so the bough shrinks
     without shearing — see the note on the aspect lock at the top. */
  body[data-theme-id="january"] {
    --jan-field: clamp(3.6rem, 9vh, 5.2rem);
    --jan-bough-w: min(17rem, 58vw);
  }

  body[data-theme-id="january"] main h2,
  body[data-theme-id="january"] .heading-section--level-2 > .heading-section__summary > .heading-section__trigger {
    letter-spacing: 0.14em;
  }

  body[data-theme-id="january"] main h3,
  body[data-theme-id="january"] .heading-section--level-3 > .heading-section__summary > .heading-section__trigger {
    letter-spacing: 0.11em;
  }

  body[data-theme-id="january"] .eyebrow {
    letter-spacing: 0.24em;
  }

  body[data-theme-id="january"] .time-bar {
    letter-spacing: 0.1em;
  }

  /* The sun moves in from the corner so it is not sitting under the brand, and
     shrinks with the frame. */
  body[data-theme-id="january"] .night-sky {
    background:
      radial-gradient(circle 1.8rem at 72% 12%, rgba(242, 230, 210, 0.92) 0 42%, rgba(242, 230, 210, 0.26) 62%, transparent 78%),
      radial-gradient(circle 5rem at 72% 12%, rgba(242, 230, 210, 0.3), transparent 72%),
      radial-gradient(ellipse 90% 30% at 50% 104%, rgba(242, 230, 210, 0.72), transparent 76%),
      linear-gradient(180deg, transparent 0 64%, rgba(178, 173, 162, 0.28) 80%, rgba(178, 173, 162, 0.1) 93%, transparent 100%),
      linear-gradient(
        180deg,
        #c5c0b7 0%,
        #ccc8bf 16%,
        #d3d0c8 34%,
        #dddad4 54%,
        #ebe4d7 72%,
        #f2e6d2 88%,
        #f2e6d2 100%
      );
    background-repeat: no-repeat;
  }

  /* Two passes instead of four, and the tiles come in with the viewport so the
     stalk COUNT stays roughly constant rather than the spacing stretching. Both
     passes keep their irregular offsets — evenly spaced stalks read as a comb at
     any width, and a 360px screen is where that is most obvious. */
  body[data-theme-id="january"] .night-sky::before {
    height: clamp(1.1rem, 2.8vh, 1.8rem);
    background-image:
      linear-gradient(
        90deg,
        transparent 0 8px,
        rgba(103, 97, 87, 0.54) 8px 9.2px,
        transparent 9.2px 31px,
        rgba(103, 97, 87, 0.44) 31px 32px,
        transparent 32px 57px,
        rgba(103, 97, 87, 0.5) 57px 58.2px,
        transparent 58.2px 88px,
        rgba(103, 97, 87, 0.4) 88px 89px,
        transparent 89px
      ),
      linear-gradient(
        90deg,
        transparent 0 4px,
        rgba(170, 165, 155, 0.3) 4px 4.8px,
        transparent 4.8px 14px,
        rgba(170, 165, 155, 0.26) 14px 14.7px,
        transparent 14.7px 25px,
        rgba(170, 165, 155, 0.28) 25px 25.8px,
        transparent 25.8px
      );
    background-size: 121px 100%, 33px 40%;
    background-position: left bottom, 5px bottom;
  }

  /* Half the flakes and half the streaks. Tile sizes double rather than the
     gradient count changing, so the loop distances below stay valid — the
     layers still travel exactly one tile and the seams stay closed. */
  body[data-theme-id="january"] .night-sky__stars--far {
    background-image:
      radial-gradient(circle at 12% 18%, rgba(159, 153, 142, 0.78) 0 1.1px, transparent 1.9px),
      radial-gradient(circle at 63% 41%, rgba(168, 163, 153, 0.66) 0 0.9px, transparent 1.6px),
      radial-gradient(circle at 34% 72%, rgba(159, 153, 142, 0.6) 0 1px, transparent 1.7px);
    background-position: 0 0, 6rem 3rem, 13rem 8rem;
  }

  body[data-theme-id="january"] .night-sky__stars--near {
    inset: 78% -14rem -3rem -3rem;
    background-image:
      radial-gradient(ellipse 1.6rem 0.075rem at 22% 26%, rgba(155, 149, 136, 0.62) 0 42%, transparent 100%),
      radial-gradient(ellipse 2.2rem 0.06rem at 41% 79%, rgba(177, 172, 161, 0.5) 0 42%, transparent 100%);
    background-size: 12rem 4rem, 12rem 7.5rem;
    background-position: 0 0, 7rem 3rem;
  }
}

/* ---------------------------------------------------------------------------
   REDUCED MOTION. Month blocks set their ambient motion on higher-specificity
   selectors than the generic .night-sky rules in main.css, so they need their
   own entry here or nothing stops.

   Everything freezes where it stands. Every flake, streak, stalk and drift is
   still painted, so the still frame is the complete picture and nothing is
   lost — only the travel is removed. That was already true of the first frame
   before any animation ran; this theme has no entrance animation and nothing is
   gated behind motion.
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  body[data-theme-id="january"] .night-sky::before,
  body[data-theme-id="january"] .night-sky__stars--far,
  body[data-theme-id="january"] .night-sky__stars--near,
  body[data-theme-id="january"] .brand a {
    animation: none !important;
    transform: none !important;
  }

  body[data-theme-id="january"] a:hover,
  body[data-theme-id="january"] a:focus-visible {
    animation: none;
  }
}

/* ---------------------------------------------------------------------------
   REDUCED DATA. Motion off, and the two layers that cost real fill are cut back
   to their cheapest legible form: the veil drops to two flake passes and the
   spindrift to two streak passes, both left as a still image. Still recognisably
   weather, at roughly half the paint. The bough, the field and the treeline are
   single static paints and stay exactly as they are.
   --------------------------------------------------------------------------- */
@media (prefers-reduced-data: reduce) {
  body[data-theme-id="january"] .night-sky::before,
  body[data-theme-id="january"] .night-sky__stars--far,
  body[data-theme-id="january"] .night-sky__stars--near,
  body[data-theme-id="january"] .brand a {
    animation: none;
    transform: none;
  }

  body[data-theme-id="january"] .night-sky__stars--far {
    inset: -2rem;
    background-image:
      radial-gradient(circle at 12% 18%, rgba(159, 153, 142, 0.78) 0 1.1px, transparent 1.9px),
      radial-gradient(circle at 63% 41%, rgba(168, 163, 153, 0.66) 0 0.9px, transparent 1.6px);
    background-position: 0 0, 6rem 3rem;
  }

  body[data-theme-id="january"] .night-sky__stars--near {
    inset: 74% -2rem -2rem;
    background-image:
      radial-gradient(ellipse 1.6rem 0.075rem at 22% 26%, rgba(155, 149, 136, 0.62) 0 42%, transparent 100%),
      radial-gradient(ellipse 2.2rem 0.06rem at 41% 79%, rgba(177, 172, 161, 0.5) 0 42%, transparent 100%);
    background-size: 12rem 4rem, 12rem 7.5rem;
    background-position: 0 0, 7rem 3rem;
  }

  /* The crystal scatter is the only part of the card that costs meaningful
     fill; on a metered connection the pane keeps its rime edges and drops the
     dots. */
  body[data-theme-id="january"] .breadcrumb-nav {
    background:
      repeating-linear-gradient(
        90deg,
        rgba(242, 230, 210, 0.95) 0 1px,
        rgba(175, 168, 154, 0.3) 1px 1.8px,
        transparent 1.8px 6px
      ) left top / 100% 0.55rem repeat-x,
      repeating-linear-gradient(
        90deg,
        rgba(242, 230, 210, 0.9) 0 1px,
        rgba(175, 168, 154, 0.26) 1px 1.7px,
        transparent 1.7px 9px
      ) left bottom / 100% 0.42rem repeat-x,
      linear-gradient(
        180deg,
        rgba(242, 230, 210, 0.88) 0%,
        rgba(242, 230, 210, 0.8) 44%,
        rgba(242, 230, 210, 0.76) 100%
      );
  }

  body[data-theme-id="january"] a:hover,
  body[data-theme-id="january"] a:focus-visible {
    animation: none;
  }
}

/* ===========================================================================
   JANUARY BY NIGHT — the counterpart lighting.

   Everything above is January's canonical state and is untouched: a body with
   no data-mode is still the flat white field under overcast, which is what the
   server sends and what a reader with JS off keeps for good. Every selector
   below carries the second attribute as well, so it lands at (0,2,x) against
   the base's (0,1,x) and wins on specificity rather than on order — which
   matters, because every theme sheet in this project loads on every page.

   THE SAME FIELD AFTER DARK. Nothing is added and nothing is taken away. The
   bough still overhangs the corner, the stalks still stand on the drift line,
   the snow still blows sideways, and the berry is still the only live colour.
   The exposure drops five stops and that is the whole change. Two observations
   carry it:

     1  THE SNOW KEEPS THE LIGHT. An overcast winter night over a snow field is
        not black. The deck traps what light there is and the field throws it
        back up into the cloud, so the ground stays the brightest broad surface
        in the frame and the sky stays the darkest. That is exactly the
        relationship the daylight sky spends four gradient stops protecting —
        "holding the sky two steps darker is what lets the field read as
        ground" — and it survives the flip intact. Only the reason changes: by
        day the field is brighter because the sun is on it, by night because
        the cloud is lit from underneath by the field itself.

     2  THE SUN BECOMES A PATCH, NOT A DISC. By day the sun is a wan white
        circle you can look straight at. At night the moon is BEHIND the same
        deck, so what shows is only the place where the deck is thin: a soft
        break at the same 76% / 15%, with no edge on it anywhere.

   THE LADDER IS READ BY ROLE, NOT BY NAME. Every name in the neutral ramp was
   taken from the daylight picture — "shadow" is the darkest ink because in
   daylight the darkest ink is a shadow, "snow" is the page because in daylight
   the page is a snow field. Renaming a token would break every rule that reads
   it, so the names hold and the VALUES move: a step that carried text by day
   carries text by night, a step that was scenery stays scenery, a step that
   was a ground stays a ground. The three groups the base block names are the
   same three groups here, inverted together. Nothing crosses between them, and
   nothing from branch/haze/sky/drift is allowed under a glyph in either mode.

   Two steps do not move at all. --jan-frost and --jan-rime are frozen water,
   and frozen water is the palest thing in the frame under any light; what
   changes at night is how much of it you can see, not what colour it is. Frost
   is also the type on the table header, and darkening it would have put dark
   letters on a dark bar for no reason at all.

   THE CEILING. The daylight sheet measured every accent against the page
   ground, because on a light page the page ground is the worst case. At night
   the ink is light and the worst case inverts: it is now the BRIGHTEST thing a
   line of type can cross, which is the snow-glow band just above the drift
   line. Nothing in this scene composites brighter than #202c3a, and the
   weakest accent there — --jan-rose, the berry — still measures 4.7:1; every
   other accent clears 5:1. Two things sit above that cap and are allowed to,
   because they are marks rather than fields: the lit rim along the drift crest
   is about three pixels tall, and the blowing snow is single pixels. The
   daylight block makes the same allowance for its stalk hairlines.

   NO NEW MOTION. Not one animation, duration or keyframe is restated below.
   The veil still drifts on januarySnowVeil and the spindrift still skates on
   januarySpindrift, at the same speeds over the same tiles; only their colour
   changes, because snow blows at night too. Leaving `animation` untouched is
   also what keeps the reduced-motion and reduced-data blocks above working —
   they cancel travel at (0,2,x), and a night rule restating `animation` would
   outrank them and quietly switch it back on.
   =========================================================================== */
body[data-theme-id="january"][data-mode="night"] {
  /* ---- The neutral ramp, inverted by role ------------------------------
     Same ten steps, same constant blue cast, same three groups. The text group
     is now the light end and the ground group the dark end; the scenery group
     stays between them and is still never allowed under a glyph. Ratios are
     against the page ground #0d131b unless noted. */
  --jan-shadow: #f2e6d2;      /* 17.4  the extreme ink */
  --jan-ink: #dad7ce;         /* 13.0  body text, 10.5 over the snow field */
  --jan-steel: #c6c1b8;       /* 10.4  soft text, footer over the field 6.1 */
  --jan-slate: #b3ada2;       /*  8.5  muted, 6.9 over the snow field */
  --jan-branch: #5c5549;      /* scenery: the bough against the deck */
  --jan-haze: #4b4237;        /* scenery: the bank that swallows the treeline */
  --jan-sky: #342e25;         /* scenery */
  --jan-drift: #26211a;       /* the raised surface, --tt-bg-alt */
  --jan-snow: #15120e;        /* the page ground — the field with no light on it */
  /* --jan-frost and --jan-rime are deliberately absent. See the note above. */
  /* Link-hover re-paired to THIS block's ground (standing rule 2026-08-14):
     #0d131b is dark, so night takes #FF465A — 5.57:1, the counterpart of the
     #BD0014 the unmoded (day) block uses at #e8eef2. */
  --link-hover: #FF4947;

  /* ---- The accents, lifted to lamp weight ------------------------------
     The same nine hues to within three degrees, moved up the value axis until
     they carry on the new ground instead of down it. The number after each is
     its contrast against #202c3a, the brightest composite in the night scene,
     which is the ratio that actually has to hold — a heading crossing the
     snow-glow band is the hardest case on the page. The floor is 4.5:1 and the
     weakest is 4.7, so every one of them may still carry an h6 at 11px, where
     the 3:1 large-text allowance does not apply. They are also still spread
     across the wheel rather than bunched, which is what keeps the heading
     gradient a gradient and not one smudge. */
  --jan-rose: #ff5e5c;        /* 4.7  winterberry under a lamp — THE anchor */
  --jan-rose-deep: #ffa1a1;   /* 7.3  the berry at its most legible */
  --jan-plum: #fc8180;        /* 5.8  rose hip gone over */
  --jan-rust: #e59158;        /* 5.8  dead oak leaf still hanging */
  --jan-sun: #d9bd63;         /* 7.7  the thin sun, tarnished brass */
  --jan-pine: #89bd88;        /* 6.6  the one evergreen on the line */
  --jan-ice: #b7b683;         /* 6.9  glacier blue — the link accent */
  --jan-indigo: #b69477;      /* 5.1  the cold hour before dusk */
  --jan-violet: #c59285;      /* 5.2  long winter shadow on snow */

  /* All three heading gradients and every structural border are declared in
     the base block as var() chains onto the ramp above, so re-pointing the
     ramp re-lights the whole frame system, the rails and the heading spectrum
     for free. None of them is restated here, and none of them should be. */

  /* Night has bloom, and this is the one token the daylight block zeroes
     outright: "Daylight, and a light ground: a bloom would be a smear." On a
     dark card the same bloom is what a lit instrument does, so it comes back. */
  --tt-breadcrumb-glow: rgba(255, 94, 92, 0.45);
  /* And the glyph halo inverts with the card under it. By day this is the
     berry's own SHADOW, cast dark because a bright halo on near-white glass is
     invisible; at night the card is dark and the same halo has to be light or
     the chips lose their only hover and focus affordance. Still cast from
     text-shadow on the character and drop-shadow on the moon, so it traces the
     glyph and can never render as a box. Never a border, in either mode. */
  --zodiac-glow: rgba(255, 159, 159, 0.62);
  /* Back to the :root default. A struck stroke on a dark card is lit from
     above, so the lip below the letter is black — the exact opposite of the
     value the base block sets for frosted glass. */
  --tt-engrave: 0 1px 0 rgba(0, 0, 0, 0.55);
  --border-dim: rgba(179, 173, 162, 0.22);
  --border-teal: rgba(179, 173, 162, 0.4);
  background: var(--jan-snow);
  color: var(--jan-ink);
  color-scheme: dark;
}

/* The frost striation stays, and stays LIGHT: rime catches light rather than
   blocking it, so the two crossing passes are the same white as by day. Only
   the alpha comes down. This layer sits at z-index 5, above the text, and on a
   near-black page a white hairline subtracts far more contrast per unit alpha
   than it does on white — 0.035/0.022 over the same ~20% duty cycle keeps the
   effective veil under one percent, which is where the measured ratios hold. */
body[data-theme-id="january"][data-mode="night"]::before {
  background:
    repeating-linear-gradient(
      96deg,
      rgba(242, 230, 210, 0.035) 0 1px,
      transparent 1px 6px
    ),
    repeating-linear-gradient(
      -84deg,
      rgba(242, 230, 210, 0.022) 0 1px,
      transparent 1px 9px
    );
}

/* THE SKY. Same five layers in the same order, same geometry, five stops down.
   The deck still runs darkest at the top and brightest just above the drift
   line — the daylight block calls that "the single strongest cue that this is
   daylight", and it is a happy accident of a snow field that the direction is
   right at night too, for the opposite reason: the cloud is being lit from
   below by the ground.

   The sun's disc and halo become one soft break in the deck with no edge on
   it, because the moon is behind the cloud rather than in front of it. The
   pooled light off the snow stays where it was and drops to 0.08 alpha, which
   is the number the ceiling is set by: any higher and the band it makes just
   above the horizon takes --jan-rose under 4.5:1. */
body[data-theme-id="january"][data-mode="night"] .night-sky {
  background:
    /* the thin place in the deck where the moon is */
    radial-gradient(circle 3.4rem at 76% 15%, rgba(233, 225, 215, 0.12) 0 46%, rgba(233, 225, 215, 0.05) 70%, transparent 84%),
    radial-gradient(circle 9rem at 76% 15%, rgba(220, 211, 198, 0.05), transparent 74%),
    /* snow-glow: the field throwing light back up into the cloud */
    radial-gradient(ellipse 90% 34% at 50% 104%, rgba(182, 171, 154, 0.08), transparent 76%),
    /* the far bank of haze, on the same wide stops for the same reason — a
       tighter band leaves a visible seam across the middle of an empty sky, and
       an empty sky is even emptier at night */
    linear-gradient(180deg, transparent 0 52%, rgba(74, 65, 54, 0.26) 74%, rgba(74, 65, 54, 0.1) 90%, transparent 100%),
    /* the deck, still holding two steps darker than the field at the horizon */
    linear-gradient(
      180deg,
      #0f0a04 0%,
      #120d05 16%,
      #15110d 34%,
      #191612 54%,
      #1e1a14 72%,
      #221d17 88%,
      #272019 100%
    );
  background-repeat: no-repeat;
}

/* THE TREELINE. Identical geometry — the same four hand-placed passes at the
   same irregular offsets and the same four coprime periods, so the barcode the
   daylight comment warns about is avoided the same way. Only the ink changes:
   by day the stalks are mid blue-greys standing against a bright overcast, at
   night they are near-black against a dim one. They still read, because they
   stand exactly where the sky is brightest.

   background-size and background-position are NOT restated, so the four
   layers stay in register with the four values the base rule sets. Any night
   pass that changed the layer count would silently shift that list. */
body[data-theme-id="january"][data-mode="night"] .night-sky::before {
  background-image:
    linear-gradient(
      90deg,
      transparent 0 11px,
      rgba(11, 7, 3, 0.82) 11px 12.4px,
      transparent 12.4px 43px,
      rgba(11, 7, 3, 0.72) 43px 44.2px,
      transparent 44.2px 78px,
      rgba(11, 7, 3, 0.78) 78px 79.5px,
      transparent 79.5px 121px,
      rgba(11, 7, 3, 0.64) 121px 122.1px,
      transparent 122.1px 152px,
      rgba(11, 7, 3, 0.74) 152px 153.3px,
      transparent 153.3px
    ),
    linear-gradient(
      96deg,
      transparent 0 9px,
      rgba(16, 13, 9, 0.66) 9px 10.1px,
      transparent 10.1px 37px,
      rgba(16, 13, 9, 0.6) 37px 38px,
      transparent 38px 66px,
      rgba(16, 13, 9, 0.68) 66px 67.2px,
      transparent 67.2px 94px,
      rgba(16, 13, 9, 0.56) 94px 95px,
      transparent 95px 113px,
      rgba(16, 13, 9, 0.62) 113px 114.1px,
      transparent 114.1px
    ),
    linear-gradient(
      84deg,
      transparent 0 6px,
      rgba(24, 20, 15, 0.56) 6px 7px,
      transparent 7px 29px,
      rgba(24, 20, 15, 0.5) 29px 29.9px,
      transparent 29.9px 51px,
      rgba(24, 20, 15, 0.58) 51px 52.1px,
      transparent 52.1px 74px,
      rgba(24, 20, 15, 0.46) 74px 74.9px,
      transparent 74.9px
    ),
    linear-gradient(
      90deg,
      transparent 0 4px,
      rgba(32, 28, 21, 0.44) 4px 4.8px,
      transparent 4.8px 15px,
      rgba(32, 28, 21, 0.38) 15px 15.7px,
      transparent 15.7px 27px,
      rgba(32, 28, 21, 0.4) 27px 27.8px,
      transparent 27.8px
    );
}

/* THE BOUGH. The clip-path is untouched — it is the same branch, and the
   geometry note at the top of this file (twelve-segment arc, ten twigs at ten
   angles, aspect locked so the drawing cannot shear) applies unchanged. Only
   the fill flips: by day bare wood halates against a bright overcast and
   washes out toward the fine ends, at night it is a silhouette and the
   gradient runs the other way, darkest where it is thinnest against the sky.
   The lightest point of it is #1e2733, which is under the scene ceiling, so
   even the worst overlap with body copy still measures better than 5:1. */
body[data-theme-id="january"][data-mode="night"] .night-sky::after {
  background: linear-gradient(252deg, #1b1711 0%, #231e18 46%, #27231c 74%, #2a251f 100%);
}

/* THE WEATHER. The single most counter-intuitive line in the daylight block is
   "Both layers are GREY, not white ... snow silhouetted against a bright
   overcast sky is darker than the sky behind it, so white flakes on this
   ground would be literally invisible." At night that inverts exactly: the
   same snow against a dark sky is the lighter thing, so the flakes go pale.
   Same five gradients, same one 26rem x 20rem tile, same travel, so the
   diagonal loop is still seamless. */
body[data-theme-id="january"][data-mode="night"] .night-sky__stars--far {
  opacity: 0.55;
  background-image:
    radial-gradient(circle at 12% 18%, rgba(227, 221, 209, 0.76) 0 1.1px, transparent 1.9px),
    radial-gradient(circle at 63% 41%, rgba(215, 206, 193, 0.64) 0 0.9px, transparent 1.6px),
    radial-gradient(circle at 34% 72%, rgba(227, 221, 209, 0.58) 0 1px, transparent 1.7px),
    radial-gradient(circle at 84% 88%, rgba(203, 194, 179, 0.5) 0 0.8px, transparent 1.5px),
    radial-gradient(circle at 47% 6%, rgba(215, 206, 193, 0.44) 0 0.7px, transparent 1.4px);
}

/* Ground blizzard, pale for the same reason. Every streak stays under 2.2rem
   and the band still starts at 74%, below the reading column — long parallel
   marks ruled across a page read as a damaged screen rather than as weather,
   and a dark page shows that artefact more clearly than a white one, not less.
   The five unrelated tile heights and the single shared 12rem width are left
   exactly as the base sets them. */
body[data-theme-id="january"][data-mode="night"] .night-sky__stars--near {
  opacity: 0.34;
  background-image:
    radial-gradient(ellipse 1.6rem 0.075rem at 22% 26%, rgba(222, 214, 201, 0.6) 0 42%, transparent 100%),
    radial-gradient(ellipse 1.1rem 0.065rem at 68% 54%, rgba(208, 200, 186, 0.52) 0 42%, transparent 100%),
    radial-gradient(ellipse 2.2rem 0.06rem at 41% 79%, rgba(197, 188, 173, 0.48) 0 42%, transparent 100%),
    radial-gradient(ellipse 0.9rem 0.08rem at 87% 12%, rgba(222, 214, 201, 0.54) 0 42%, transparent 100%),
    radial-gradient(ellipse 1.4rem 0.07rem at 9% 62%, rgba(208, 200, 186, 0.48) 0 42%, transparent 100%);
}

/* THE FIELD. Same eighteen-point drift line, same shallow amplitude — past
   about 15% it stops reading as wind-packed snow and starts reading as hills,
   and that is a daylight observation that has nothing to do with the light.

   The fill inverts in the useful direction: the crest still catches what light
   there is and the near field is still in its own shadow, so the ramp runs the
   same way at a fifth of the value. The hollows between drifts go from a blue
   wash to a genuine absence of light, which is what a hollow is at night.

   The undercut band flips sign. By day it is a dark blue shadow, there because
   "a white field meeting a pale sky with nothing between them reads as an
   unfinished gradient". At night the field and the sky are only two steps
   apart, so the separator has to be the LIT rim on the crest instead. It is
   about three pixels tall, which is why it is allowed above the scene ceiling:
   it is a line, never a reading surface. */
body[data-theme-id="january"][data-mode="night"] .night-sky__aurora {
  background:
    radial-gradient(ellipse 22rem 2.4rem at 24% 104%, rgba(12, 9, 6, 0.55), transparent 72%),
    radial-gradient(ellipse 16rem 1.8rem at 68% 108%, rgba(12, 9, 6, 0.45), transparent 70%),
    linear-gradient(180deg, transparent 0 3%, rgba(185, 173, 155, 0.2) 9%, rgba(155, 143, 125, 0.08) 20%, transparent 38%),
    linear-gradient(180deg, #2e2820 0%, #2a251d 22%, #231f18 58%, #1c1812 100%);
  background-repeat: no-repeat;
}

/* THE CARD. The same pane of cold glass with rime creeping in from all four
   edges, unlit. The two-stop needle survives intact and is the reason this
   works at all: a white hairline immediately followed by a contrasting one is
   what makes a crystal read as raised, and at night only the second half has
   to change sign — the shadow beside the highlight can no longer be a
   blue-grey lighter than the glass, so it becomes a near-black darker than it.
   Four periods still 6/8/9/11px so opposite edges never mirror. Static. */
body[data-theme-id="january"][data-mode="night"] .breadcrumb-nav {
  background:
    repeating-linear-gradient(
      90deg,
      rgba(242, 230, 210, 0.5) 0 1px,
      rgba(6, 4, 1, 0.6) 1px 1.8px,
      transparent 1.8px 6px
    ) left top / 100% 0.55rem repeat-x,
    repeating-linear-gradient(
      90deg,
      rgba(242, 230, 210, 0.42) 0 1px,
      rgba(6, 4, 1, 0.55) 1px 1.7px,
      transparent 1.7px 9px
    ) left bottom / 100% 0.42rem repeat-x,
    repeating-linear-gradient(
      0deg,
      rgba(242, 230, 210, 0.4) 0 1px,
      rgba(6, 4, 1, 0.55) 1px 1.7px,
      transparent 1.7px 8px
    ) left top / 0.42rem 100% repeat-y,
    repeating-linear-gradient(
      0deg,
      rgba(242, 230, 210, 0.36) 0 1px,
      rgba(6, 4, 1, 0.5) 1px 1.6px,
      transparent 1.6px 11px
    ) right top / 0.36rem 100% repeat-y,
    radial-gradient(circle at 30% 40%, rgba(240, 231, 210, 0.34) 0 0.8px, transparent 1.5px)
      0 0 / 19px 15px repeat,
    radial-gradient(circle at 70% 65%, rgba(156, 145, 125, 0.2) 0 0.7px, transparent 1.4px)
      7px 5px / 27px 23px repeat,
    linear-gradient(
      180deg,
      rgba(32, 28, 21, 0.92) 0%,
      rgba(24, 20, 15, 0.9) 44%,
      rgba(16, 13, 9, 0.88) 100%
    );
  box-shadow:
    inset 0 1px 0 rgba(242, 230, 210, 0.09),
    inset 0 -1px 0 rgba(0, 0, 0, 0.5),
    0 2px 10px rgba(0, 0, 0, 0.45);
}

/* The same pass of light crossing the pane, at the alpha a night reading takes.
   Same element, same keyframe, same duration. */
body[data-theme-id="january"][data-mode="night"] .breadcrumb-nav::before {
  background: linear-gradient(
    90deg,
    transparent,
    rgba(241, 231, 210, 0.18),
    rgba(182, 170, 147, 0.1),
    transparent
  );
}

/* The brand goes from black ink cut into frost to frost cut into the dark: the
   one-pixel lift under the letters flips from white to black for the same
   reason --tt-engrave does. Hover is still the winterberry marking the one
   thing alive in the field, and at night it may carry a little bloom. */
body[data-theme-id="january"][data-mode="night"] .brand a {
  color: var(--jan-frost);
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.6);
}

body[data-theme-id="january"][data-mode="night"] .brand a:hover {
  color: var(--jan-rose);
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.6), 0 0 18px rgba(255, 94, 92, 0.38);
}

/* Headings keep the grotesque, the tracking and the drop-shadow technique —
   it still has to be a FILTER and not a text-shadow, because the glyphs are
   painted with background-clip: text and a text-shadow would render through
   the transparent fill and bury the gradient under a slab. Only the colour of
   the cut inverts: type cut into ice takes a white lip, type cut into a dark
   field takes a black one. */
body[data-theme-id="january"][data-mode="night"] main h1,
body[data-theme-id="january"][data-mode="night"] .page-title,
body[data-theme-id="january"][data-mode="night"] main h2,
body[data-theme-id="january"][data-mode="night"] main h3,
body[data-theme-id="january"][data-mode="night"] main h4,
body[data-theme-id="january"][data-mode="night"] main h5,
body[data-theme-id="january"][data-mode="night"] main h6,
body[data-theme-id="january"][data-mode="night"] .markdown-page .heading-section__trigger {
  filter: var(--heading-tint) drop-shadow(0 1px 0 rgba(0, 0, 0, 0.62));
}

/* LINKS. The night-mode underline rgbas that used to live here are gone along
   with the day-mode underline they coloured (removed above per the standing
   no-underline rule, 2026-08-14) — --jan-ice against body ink is 1.43:1 at
   night, an even weaker case for colour alone than day's 6.06:1, but that gap
   is a link-camouflage-level question, not one this file can answer with a
   rule under the word any more. See the LINKS comment in the unmoded block
   above. */

/* SURFACES. Every one of these already had a fill in the base block; each is
   the same object seen in the dark. Nothing gains a background it did not have
   — there is one shared site background and neither mode adds a second. An
   inset panel stops being cleared ice lit from above and becomes a well, so
   the hairline under its top edge flips from white to black. */
body[data-theme-id="january"][data-mode="night"] input,
body[data-theme-id="january"][data-mode="night"] textarea,
body[data-theme-id="january"][data-mode="night"] select,
body[data-theme-id="january"][data-mode="night"] code,
body[data-theme-id="january"][data-mode="night"] pre {
  background: rgba(224, 216, 203, 0.06);
}

body[data-theme-id="january"][data-mode="night"] input,
body[data-theme-id="january"][data-mode="night"] textarea,
body[data-theme-id="january"][data-mode="night"] select,
body[data-theme-id="january"][data-mode="night"] pre {
  box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.45);
}

/* The table header is still the month's biggest single field of red, but a
   field of colour with no light on it is that colour over the dark rather than
   a painted bar — a bright #ff5c66 slab would be the loudest thing on a night
   page by a wide margin, and the anchor is supposed to read as scarce. The
   type stays --jan-frost and gains contrast rather than losing it: 14:1. */
body[data-theme-id="january"][data-mode="night"] th {
  background: rgba(255, 94, 92, 0.18);
}

/* Highlighted text: the same winterberry wash, at the alpha it takes to be
   seen over a dark page, with the paler berry as its type at 7.7:1. */
body[data-theme-id="january"][data-mode="night"] mark {
  background: rgba(255, 94, 92, 0.16);
}

/* Still no left rule on quotes — border-left belongs to <a> inside ul/ol and
   is used nowhere in this file, in either mode. The inset wash is the shadow a
   raised block casts on snow, and at night that shadow is cast by the sky, so
   it goes pale rather than dark. */
body[data-theme-id="january"][data-mode="night"] blockquote {
  box-shadow: inset 1rem 0 1.4rem -1.2rem rgba(179, 173, 162, 0.4);
}

/* On a light ground a glow does nothing and a shadow does everything; on a
   dark one the reverse is true, so the cards trade their cast shadow for a lit
   top edge and keep only enough shadow to seat them. */
body[data-theme-id="january"][data-mode="night"] .hero-card,
body[data-theme-id="january"][data-mode="night"] .folder-section {
  box-shadow:
    inset 0 1px 0 rgba(242, 230, 210, 0.07),
    0 2px 10px rgba(0, 0, 0, 0.4);
}

body[data-theme-id="january"][data-mode="night"] .hero-card:hover,
body[data-theme-id="january"][data-mode="night"] .folder-section:hover {
  box-shadow:
    inset 0 1px 0 rgba(242, 230, 210, 0.11),
    0 4px 16px rgba(0, 0, 0, 0.5);
}

/* Chrome, still selected by CLASS and never by element — `button` would reach
   the moon chip, which is a <button> while the signs are anchors, and half the
   strip would drift away from the other half. That trap does not change with
   the light. */
body[data-theme-id="january"][data-mode="night"] .time-bar,
body[data-theme-id="january"][data-mode="night"] .sitemap-link,
body[data-theme-id="january"][data-mode="night"] .calendar-app__nav,
body[data-theme-id="january"][data-mode="night"] .calendar-app__today {
  background: rgba(224, 216, 203, 0.05);
  box-shadow: inset 0 1px 0 rgba(242, 230, 210, 0.07);
}

body[data-theme-id="january"][data-mode="night"] .sitemap-link:hover,
body[data-theme-id="january"][data-mode="night"] .calendar-app__nav:hover,
body[data-theme-id="january"][data-mode="night"] .calendar-app__today:hover,
body[data-theme-id="january"][data-mode="night"] .sitemap-link:focus-visible,
body[data-theme-id="january"][data-mode="night"] .calendar-app__nav:focus-visible,
body[data-theme-id="january"][data-mode="night"] .calendar-app__today:focus-visible {
  background: rgba(224, 216, 203, 0.1);
  box-shadow:
    inset 0 1px 0 rgba(242, 230, 210, 0.11),
    0 2px 8px rgba(0, 0, 0, 0.45);
}

/* THE ZODIAC CHIPS STILL CARRY NO FRAME, IN EITHER MODE. The pin in the base
   block is at (0,2,x) and already covers both, since a night body still
   matches body[data-theme-id="january"]. Nothing is restated here on purpose:
   there is no border, border-image, outline ring or box-shadow anywhere in
   this counterpart to undo, and a box-shadow on a chip IS a border because it
   paints the element's bounding rectangle. Their whole hover and focus
   affordance is --zodiac-glow above, which flipped light with the card. */

/* The astrolabe's face is a plate of rime lit from in front by day. At night
   there is nothing lighting it, so the same white drops to a breath — the
   engraved rings and the moon's limb are artwork inside the illustration and
   still read, which is the point of leaving the fill alone and moving only its
   opacity. */
body[data-theme-id="january"][data-mode="night"] .zodiac-clock .zc-face {
  fill-opacity: 0.07;
}

body[data-theme-id="january"][data-mode="night"] .celestial-tooltip {
  background: rgba(23, 19, 14, 0.97);
  box-shadow: 0 6px 22px rgba(0, 0, 0, 0.55);
}

/* The scrollbar's highlight runs the other way: lit from the left on glass,
   from the right in the dark. */
body[data-theme-id="january"][data-mode="night"]::-webkit-scrollbar-thumb,
body[data-theme-id="january"][data-mode="night"] ::-webkit-scrollbar-thumb {
  background-image: linear-gradient(
    90deg,
    rgba(0, 0, 0, 0.35) 0%,
    rgba(242, 230, 210, 0) 46%,
    rgba(240, 231, 210, 0.12) 100%
  );
}

/* CALENDAR. Today's cell and the two hover washes are the anchor at low alpha,
   and low alpha over white is not the same number as low alpha over near
   black. The berry ring on today is var(--jan-rose) and re-lights itself. */
body[data-theme-id="january"][data-mode="night"] .calendar-day--today {
  background: rgba(255, 94, 92, 0.12);
}

body[data-theme-id="january"][data-mode="night"] .calendar-event__link:hover,
body[data-theme-id="january"][data-mode="night"] .calendar-event__link:focus-visible,
body[data-theme-id="january"][data-mode="night"] .calendar-subscribe__action:hover,
body[data-theme-id="january"][data-mode="night"] .calendar-subscribe__action:focus-visible {
  background: rgba(255, 94, 92, 0.14);
}

body[data-theme-id="january"][data-mode="night"] .calendar-subscribe {
  background: rgba(224, 216, 203, 0.04);
}

/* ---------------------------------------------------------------------------
   RESPONSIVE, AT NIGHT. The four geometry variables are deliberately NOT
   restated in the night block above, so the mobile block's --jan-field and
   --jan-bough-w still govern and the horizon, the stalks and the field stay in
   register. What does need restating is every layer the mobile block repaints
   with literal colours: those rules are (0,2,x) and the night rules above are
   (0,3,x), so without a night entry here a phone in dark mode would get the
   desktop night sky and a two-layer background-size list applied to a
   four-layer image.
   --------------------------------------------------------------------------- */
@media (max-width: 800px) {
  /* The break in the deck moves in from the corner so it is not sitting under
     the brand, exactly as the sun does by day. */
  body[data-theme-id="january"][data-mode="night"] .night-sky {
    background:
      radial-gradient(circle 2.4rem at 72% 12%, rgba(233, 225, 215, 0.12) 0 46%, rgba(233, 225, 215, 0.05) 70%, transparent 84%),
      radial-gradient(circle 6rem at 72% 12%, rgba(220, 211, 198, 0.05), transparent 74%),
      radial-gradient(ellipse 90% 30% at 50% 104%, rgba(182, 171, 154, 0.08), transparent 76%),
      linear-gradient(180deg, transparent 0 64%, rgba(74, 65, 54, 0.3) 80%, rgba(74, 65, 54, 0.12) 93%, transparent 100%),
      linear-gradient(
        180deg,
        #0f0a04 0%,
        #120d05 16%,
        #15110d 34%,
        #191612 54%,
        #1e1a14 72%,
        #221f19 88%,
        #28221b 100%
      );
    background-repeat: no-repeat;
  }

  /* Two passes, matching the two background-size values the mobile block sets.
     Both keep their irregular offsets — evenly spaced stalks read as a comb at
     any width, and a 360px screen is where that is most obvious. */
  body[data-theme-id="january"][data-mode="night"] .night-sky::before {
    background-image:
      linear-gradient(
        90deg,
        transparent 0 8px,
        rgba(11, 7, 3, 0.82) 8px 9.2px,
        transparent 9.2px 31px,
        rgba(11, 7, 3, 0.7) 31px 32px,
        transparent 32px 57px,
        rgba(11, 7, 3, 0.78) 57px 58.2px,
        transparent 58.2px 88px,
        rgba(11, 7, 3, 0.64) 88px 89px,
        transparent 89px
      ),
      linear-gradient(
        90deg,
        transparent 0 4px,
        rgba(32, 28, 21, 0.46) 4px 4.8px,
        transparent 4.8px 14px,
        rgba(32, 28, 21, 0.4) 14px 14.7px,
        transparent 14.7px 25px,
        rgba(32, 28, 21, 0.42) 25px 25.8px,
        transparent 25.8px
      );
  }

  /* Three flakes and two streaks, matching the mobile layer counts exactly so
     the position and size lists stay aligned and the loops stay seamless. */
  body[data-theme-id="january"][data-mode="night"] .night-sky__stars--far {
    background-image:
      radial-gradient(circle at 12% 18%, rgba(227, 221, 209, 0.76) 0 1.1px, transparent 1.9px),
      radial-gradient(circle at 63% 41%, rgba(215, 206, 193, 0.64) 0 0.9px, transparent 1.6px),
      radial-gradient(circle at 34% 72%, rgba(227, 221, 209, 0.58) 0 1px, transparent 1.7px);
  }

  body[data-theme-id="january"][data-mode="night"] .night-sky__stars--near {
    background-image:
      radial-gradient(ellipse 1.6rem 0.075rem at 22% 26%, rgba(222, 214, 201, 0.6) 0 42%, transparent 100%),
      radial-gradient(ellipse 2.2rem 0.06rem at 41% 79%, rgba(197, 188, 173, 0.48) 0 42%, transparent 100%);
  }
}

/* ---------------------------------------------------------------------------
   REDUCED MOTION, AT NIGHT. No entry is needed and none is added. The block
   above cancels travel with `animation: none !important`, and !important beats
   any specificity, so it reaches these rules unchanged. Nothing below the
   night banner restates `animation` or `transform` for exactly that reason.

   REDUCED DATA, AT NIGHT. This one DOES need an entry. Its cut-down layers are
   written at (0,2,x) and the night rules above are (0,3,x), so a metered
   connection in dark mode would otherwise get the full flake and streak counts
   back — and, worse, the reduced-data background-position list (two values)
   applied to a five-layer image. Same cuts, same layer counts, night colours.
   --------------------------------------------------------------------------- */
@media (prefers-reduced-data: reduce) {
  body[data-theme-id="january"][data-mode="night"] .night-sky__stars--far {
    background-image:
      radial-gradient(circle at 12% 18%, rgba(227, 221, 209, 0.76) 0 1.1px, transparent 1.9px),
      radial-gradient(circle at 63% 41%, rgba(215, 206, 193, 0.64) 0 0.9px, transparent 1.6px);
  }

  body[data-theme-id="january"][data-mode="night"] .night-sky__stars--near {
    background-image:
      radial-gradient(ellipse 1.6rem 0.075rem at 22% 26%, rgba(222, 214, 201, 0.6) 0 42%, transparent 100%),
      radial-gradient(ellipse 2.2rem 0.06rem at 41% 79%, rgba(197, 188, 173, 0.48) 0 42%, transparent 100%);
  }

  /* The crystal scatter is the only part of the card that costs meaningful
     fill; the pane keeps its two rime edges and drops the dots. */
  body[data-theme-id="january"][data-mode="night"] .breadcrumb-nav {
    background:
      repeating-linear-gradient(
        90deg,
        rgba(242, 230, 210, 0.5) 0 1px,
        rgba(6, 4, 1, 0.6) 1px 1.8px,
        transparent 1.8px 6px
      ) left top / 100% 0.55rem repeat-x,
      repeating-linear-gradient(
        90deg,
        rgba(242, 230, 210, 0.42) 0 1px,
        rgba(6, 4, 1, 0.55) 1px 1.7px,
        transparent 1.7px 9px
      ) left bottom / 100% 0.42rem repeat-x,
      linear-gradient(
        180deg,
        rgba(32, 28, 21, 0.92) 0%,
        rgba(24, 20, 15, 0.9) 44%,
        rgba(16, 13, 9, 0.88) 100%
      );
  }
}

/* ---------------------------------------------------------------------------
   KEYFRAMES. Two, both transform-only, both travelling exactly one background
   tile so the loop restarts with no seam and no reset flash.

   The veil moves diagonally, which is why every gradient inside that layer
   shares one 26rem × 20rem tile: the translate has to be a whole tile on BOTH
   axes at once, and mixed tile sizes make that impossible. The spindrift moves
   on one axis, so only its widths have to agree.

   58s against 5.5s is the parallax. The far layer crosses at roughly nine
   pixels a second and the near layer at roughly thirty-five, which is what
   makes the lower band read as wind skating over the drifts rather than as more
   snow falling. Neither is fast enough to draw the eye off the text.
   --------------------------------------------------------------------------- */
@keyframes januarySnowVeil {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-26rem, 20rem, 0); }
}

@keyframes januarySpindrift {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-12rem, 0, 0); }
}
