/* ===========================================================================
   LINK CAMOUFLAGE — a link is invisible until the pointer is on it, anywhere
   on the page, and paints a colour that moves while it is being pressed.

   THE RULE. Nothing on this site may advertise that it is a link. No colour of
   its own, no underline, no glow, no drawn rule, no chip fill. A link rests in
   exactly the paint of whatever surrounds it and reveals itself only under
   :hover, :focus-visible or :active, at which point every theme's existing
   hover treatment lands untouched. The reader finds new pages by reading, not
   by scanning for coloured words.

   THE SCOPE IS THE WHOLE DOCUMENT, AND THAT IS A DECISION. This sheet used to
   stop at `main a` and carried eight carve-outs — search results, the two
   calendar link classes, the .ics controls, the sitemap button, the tag chips,
   Leaflet's map controls, the zodiac chips — on the argument that a control is
   not a page waiting to be discovered and that chrome tells a reader where they
   are. That argument is retired on purpose. The brand wordmark, the breadcrumb
   trail, the zodiac strip, the gear, the results list and the map's own zoom
   buttons all camouflage now, on the same terms as a link in a sentence.
   Restoring an exception means adding a `:not()` to the resting selector below
   and saying here why that one link is allowed to announce itself; do not
   restore the old list wholesale.

   Two things are deliberately NOT reached, because neither is an <a>: the
   separators between crumbs (`.breadcrumb-sep`, punctuation, not links) and
   every <button> on the page — the day/night switch, the theme picker's
   controls, the search submit, the trail's own reset. A button is a control
   that acts on the page you are already on; camouflage is about not signposting
   pages you have not opened yet.

   WHY THIS IS ITS OWN SHEET, LOADED LAST. The resting colour of a link is set
   in fifteen places — main.css plus the fourteen sheets in public/themes,
   several of them twice for day and night. Neutralising it at the source would
   mean fifteen edits that a sixteenth theme silently reopens. One sheet, after every
   theme in main.js's STYLESHEET_HREFS, is the single authority instead: a new
   month can paint links however it likes and this file still holds them flat at
   rest. See main.js — the href is appended AFTER the theme list on purpose, and
   the comment there says so.

   WHY `!important` NOW, WHERE SOURCE ORDER AND SPECIFICITY USED TO DO. While
   this file only had to beat the resting colour of prose links, the arithmetic
   was worth doing by hand: the heaviest resting selector in the sheets was
   `body[data-theme-id="august"][data-mode="day"] a:visited:not(.celestial-chip)`
   at (0,4,2), and a long enough run of `:not()` cleared it. Site-wide, the rule
   has to beat every link rule in every component as well — .brand a, .breadcrumbs
   a (which is already `color: … !important` at (0,2,1)), the tripled
   .celestial-chip and .instrument-gear guards at (0,3,0), .quiz-results__list a,
   november's ruled lists, Leaflet's own sheet — and that set grows every time a
   component is added. Counting it per component is a maintenance debt that comes
   due silently, as an uncamouflaged link nobody notices. `!important` on the
   resting declarations settles all of it at once, and it is safe precisely
   because the state guards mean the rule stops matching the moment the pointer
   or keyboard arrives: a theme's hover paint never has to fight it.

   The one place a fight remains is against other `!important` colour rules of
   the same origin, where specificity still decides. There is one such rule on
   the site — `.breadcrumbs a, …:visited, …:active` at (0,2,1) in main.css — so
   the resting selector's three state guards, (0,3,1), are load-bearing rather
   than decorative. Same for the press state further down, which pads with a
   repeated `:active` for exactly this reason.

   THE STATE GUARDS DO THE REVEALING. `:not(:hover):not(:focus-visible):not(:active)`
   means this rule stops matching the moment the pointer, the keyboard focus or a
   press arrives, so the theme's own rule paints with nothing from here left to
   override. That is why the resting block declares no hover state of its own:
   every month's hover — october's harvest, december's candle glow, november's
   pen stroke pressing solid, july's hotpink bloom — is preserved exactly as
   written. Keyboard focus is treated as hover deliberately; a link nobody can
   find by tabbing is not a design decision, it is a broken page. `:active` is in
   the guard for the same reason: a link activated by Enter is never :hover, and
   the press must still paint.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   THE PRESS PALETTE.

   Two colours per state, not one, because the press is an animation: the sweep
   below runs a gradient between them, so both ends have to be readable on the
   ground they sit on or the word loses letters mid-press. Scarlet for a page
   this reader has not opened in this session; lime for one they have.

   DAY AND NIGHT. The night values are the `:root` base, matching how every
   theme sheet is written. The day block keys off `body[data-mode="day"]` alone
   rather than per theme, because these are this file's own tokens and no month
   competes for them.

   An unstamped <body> — no JavaScript — takes the night values on a theme whose
   base lighting is daylight (january, and the day-lit months October and July
   send from the server). Scarlet is chosen to read on both grounds for that
   reason. Lime is not, and does not have to be: the "already seen" mark comes
   from a `data-seen` attribute that only the bootstrap in main.js writes, so
   with scripting off no link is ever lime, and with scripting on `data-mode` is
   always stamped. See the session sight-line block in main.js.
   --------------------------------------------------------------------------- */
:root {
  --link-press-deep: #d4100b;
  --link-press-crest: #ff4d2e;
  --link-press-seen-deep: #7fdc12;
  --link-press-seen-crest: #d4ff5c;
}

body[data-mode="day"] {
  --link-press-deep: #9c100e;
  --link-press-crest: #e02203;
  --link-press-seen-deep: #2f6b1a;
  --link-press-seen-crest: #5f9e00;
}

/* ---------------------------------------------------------------------------
   AT REST — every link on the page, wearing its surroundings.
   --------------------------------------------------------------------------- */
a:not(:hover):not(:focus-visible):not(:active) {
  /* Text paint. `inherit` rather than a token, so the link takes whatever the
     thing around it is wearing — body copy, a heading gradient's ink, the
     chartreuse inside a <strong>, a table cell, the tarot card's own ink under
     the breadcrumb trail — on all fifteen sheets and in both day and night
     modes, with no per-theme value to keep in step.

     -webkit-text-fill-color has to be restated: january, february, march, may,
     june, december and lava-lamp flatten every `a` with it, it inherits, and it
     beats `color` on the element it lands on. `currentColor` is its own initial
     value and resolves per element, so `color: inherit` is what actually paints
     — and so the SVG inside .instrument-gear keeps drawing with its own stroke.

     text-shadow inherits too, and that is the point of `inherit` rather than
     `none`: on a sheet whose body copy carries a glow, a link with no glow is
     just as findable as a link with the wrong colour. Camouflage means matching
     the surroundings, not going blank. */
  color: inherit !important;
  -webkit-text-fill-color: currentColor !important;
  text-shadow: inherit !important;

  /* The shorthand, so line, style, colour and thickness all reset together —
     insurance against any theme sheet that sets text-decoration longhands
     individually, the way january and november once did before the standing
     no-underline rule (2026-08-14) removed those declarations at the source. */
  text-decoration: none !important;

  /* Several components mark a link with a box rather than with ink, and a box
     is as loud as a colour: .quiz-results__list a (cyan fill plus a 2px left
     rule), november's ruled lists, the .sitemap-link and .calendar-subscribe__action
     buttons, the .tag-row__tag chips, Leaflet's white zoom squares.
     `border-color: transparent` rather than `border: 0` keeps the geometry, so
     nothing reflows when the reader hovers and the frame comes back. The
     `background` shorthand is what resets a theme's background-clip along with
     its fill, which the brand wordmark needs. */
  background: none !important;
  background-color: transparent !important;
  border-color: transparent !important;
  box-shadow: none !important;
}

/* The generated marks a link carries with it, held to the same contract. The
   only one on the site today is the brand's blinking underscore, which is pink
   against a yellow wordmark and would otherwise be the one lit thing left in
   the header. Recolouring it is allowed by the wordmark's lock in main.css;
   stopping the blink is not, so `animation` is untouched here and the cursor
   goes on blinking in the ink of the header. `content` is untouched too, so no
   mark is removed and nothing reflows. */
a:not(:hover):not(:focus-visible):not(:active)::before,
a:not(:hover):not(:focus-visible):not(:active)::after {
  color: inherit !important;
  -webkit-text-fill-color: currentColor !important;
  text-shadow: inherit !important;
  background: none !important;
  background-color: transparent !important;
  border-color: transparent !important;
  box-shadow: none !important;
}

/* ---------------------------------------------------------------------------
   THE REVEAL, FOR THE THREE SHEETS THAT HAVE NONE.

   Hiding a link at rest is only half a contract; the other half is that hover
   actually produces something. Thirteen sheets already hold up their end —
   october goes harvest, december lights its candle, november's pen stroke
   presses solid, and everything else falls through to --link-hover in
   main.css.

   MAY, JUNE and LAVA-LAMP do not, and they were the three that would have
   swallowed this feature whole. All three flatten every `a` to a single value —
   `color` AND `-webkit-text-fill-color`, #fff or #000 or the lava-lamp cream —
   at `body[data-theme-id="may"][data-mode="day"] a:not(.celestial-chip)`, which
   is (0,3,2). main.css's `a:hover` is (0,1,1) and loses, so on these three
   months a link was already identical to its surroundings in EVERY state,
   hovered or not. That was survivable while links elsewhere carried colour. It
   is not survivable now that hover is the only way anything is found, so the
   reveal is supplied here rather than left as a gap in three of fourteen sheets.

   IT IS COLOUR AGAIN, AS OF 2026-08-14 — reversing the note this comment used
   to carry. --link-hover needs no palette, because it deliberately is not drawn
   from one: it is the same red-rose hue (354°) everywhere, not a per-month
   accent. It carries two lightnesses, not one — #FF465A on dark grounds and
   #BD0014 on light ones, because a single value cannot clear 4.5:1 against both
   (see main.css's :root for the measurements). Both are the same hue, so this
   stays one decision rather than fourteen. That is
   exactly the property `font-weight: 700` used to be reached for instead, back
   when the only colour-free option was inventing an accent that would have been
   a design decision about somebody else's month. There is no longer a reason to
   reach for it, and reverting to text alone removes a real cost the
   weight shift had — a heavier glyph is usually wider, so hovering a link
   reflowed the text around it. Colour alone does not.

   THE CHIPS ARE STILL EXCLUDED HERE, AND THEY ARE STILL REVEALED. The three
   flatteners these rules answer to carry `:not(.celestial-chip)` themselves, so
   a chip on may, june or lava-lamp is painted by the tripled .celestial-chip
   guard in main.css instead — which means the moment the resting block above
   stops matching, the chip comes back gold on its own. It needs no colour
   change from here, and a rose-red glyph strip would be wrong.

   SPECIFICITY: 1 attribute + :hover + two :not() arguments = four class terms,
   body/a = two element terms, so (0,4,2) against the (0,3,2) it has to clear —
   comfortably enough to set `color` too, with no `!important` needed. The
   doubled :not(.celestial-chip) buys weight as well as the exclusion. This is
   the same trick, and the same arithmetic, that main.css writes out at
   .celestial-chip; if one of these three sheets ever adds a third attribute to
   that selector, recount here.
   --------------------------------------------------------------------------- */
body[data-theme-id="may"] a:hover:not(.celestial-chip):not(.celestial-chip),
body[data-theme-id="may"] a:focus-visible:not(.celestial-chip):not(.celestial-chip),
body[data-theme-id="june"] a:hover:not(.celestial-chip):not(.celestial-chip),
body[data-theme-id="june"] a:focus-visible:not(.celestial-chip):not(.celestial-chip),
body[data-theme-id="lava-lamp"] a:hover:not(.celestial-chip):not(.celestial-chip),
body[data-theme-id="lava-lamp"] a:focus-visible:not(.celestial-chip):not(.celestial-chip) {
  text-decoration: none;
  color: var(--link-hover);
  -webkit-text-fill-color: var(--link-hover);
}

/* ---------------------------------------------------------------------------
   UNDER THE FINGER — the press.

   Hover says "this is a link". The press says which link, and whether the
   reader has been down it already in this session: SCARLET for a page they have
   not opened, LIME for one they have. The session's memory is not `:visited` —
   that is the browser's history, months deep, and the only properties it will
   let a sheet set are colours; it cannot be animated and it cannot be scoped to
   this visit. The mark is a `data-seen` attribute written by the bootstrap in
   main.js from a sessionStorage set, cleared with the trail. See the session
   sight-line block there.

   THE COLOUR MOVES, AND IT STAYS INSIDE THE LETTERS. The paint is a gradient
   clipped to the glyphs — `background-clip: text` with a transparent text fill
   — sweeping one tile-width per cycle, so the colour travels through the word
   while the word's own shape is the hard edge of it. Nothing leaves the type:
   `text-shadow` and `box-shadow` are cancelled (the site's hover affordance is
   a hotpink bloom, and :active co-occurs with :hover under a mouse), and so is
   `text-decoration`, because a rule under the word is paint outside the word.

   THE TILE IS SIZED IN `em` AND SHIFTED BY EXACTLY ONE TILE. `background-size:
   6em 100%` with a gradient that starts and ends on the same colour repeats
   seamlessly, and a keyframe that moves `background-position` from 0 to 6em
   lands the pattern exactly where it began — so the loop has no jump, at any
   word length, without the animation needing to know the element's width.
   Percentages would not do this: against a background wider than its box they
   resolve to the overflow, not the box, and the seam moves with the word.

   `color` is set as well as the fill, and matters in three places: it is what
   an `<svg>` inside a link strokes with (the gear), what the brand's underscore
   inherits, and what paints if a browser ever fails the clip.

   SPECIFICITY. `a:active` is (0,1,1) and loses to `.breadcrumbs a:active` at
   (0,2,1), which is `!important` — so the crumb under the finger would have
   stayed breadcrumb-pink. Repeating `:active` twice more lifts the selector to
   (0,3,1) and settles it, the same way main.css triples `.celestial-chip`. The
   seen variant adds the attribute and lands at (0,4,1), which is how lime beats
   scarlet without either rule knowing about the other's order.
   --------------------------------------------------------------------------- */
a:active:active:active {
  color: var(--link-press-crest) !important;
  background-image: linear-gradient(
    90deg,
    var(--link-press-deep) 0%,
    var(--link-press-crest) 50%,
    var(--link-press-deep) 100%
  ) !important;
  background-color: transparent !important;
  background-size: 6em 100% !important;
  background-repeat: repeat !important;
  -webkit-background-clip: text !important;
  background-clip: text !important;
  -webkit-text-fill-color: transparent !important;
  text-decoration: none !important;
  text-shadow: none !important;
  box-shadow: none !important;
  animation: linkPressSweep 1.1s linear infinite !important;
}

a[data-seen]:active:active:active {
  color: var(--link-press-seen-crest) !important;
  background-image: linear-gradient(
    90deg,
    var(--link-press-seen-deep) 0%,
    var(--link-press-seen-crest) 50%,
    var(--link-press-seen-deep) 100%
  ) !important;
}

/* The marks a link carries keep the press colour but not the clip: a
   pseudo-element inherits `-webkit-text-fill-color: transparent` from the link
   and has no background of its own to show through it, which would blank the
   brand's underscore for as long as the wordmark was held down. Restating the
   fill as `currentColor` gives it the press colour from the `color` above. */
a:active:active:active::before,
a:active:active:active::after {
  -webkit-text-fill-color: currentColor !important;
  text-shadow: none !important;
}

@keyframes linkPressSweep {
  from { background-position: 0 0; }
  to { background-position: 6em 0; }
}

/* A reader who has asked for less motion still gets both press colours; what
   goes is the travel through them. The crest is the whole word, flat.

   This block is not redundant with main.css's blanket `*` rule. That one holds
   `animation-duration: 0.01ms !important` at (0,0,0), and the press above is an
   `animation` shorthand at (0,3,1) — same origin, both important, so specificity
   decides and the sweep would have gone on running. Cancelling it here, at the
   same weight as the rule that starts it, is what actually stops it. */
@media (prefers-reduced-motion: reduce) {
  a:active:active:active {
    background-image: none !important;
    -webkit-text-fill-color: currentColor !important;
    animation: none !important;
  }
}
