/* ══════════════════════════════════════════════════════════════════
   INK — the motion and detail layer
   Sept 1, 2026.

   The brand is a working sheet: someone thinking on paper. So the
   charm has to come from the page BEHAVING like paper being worked
   on, not from generic web polish. Four ideas, and nothing else
   (margin notes, once the third, were retired Sept 7, 2026):

     1. Ink draws.        Underlines stroke left to right, like a pen,
                          instead of fading a border in.
     2. Ticks get ticked. A checkbox draws its check when it arrives.
     3. Rules wipe in.    A hairline draws from the start edge.
     4. Nothing lifts.    This is flat paper. Colour and rule weight
                          carry every hover. No card ever rises.

   Everything is opt-in by class, so no existing layout moves, and
   every animation resolves to its FINISHED state under reduced
   motion rather than being disabled (a half-drawn underline is worse
   than a plain one).
   ══════════════════════════════════════════════════════════════════ */

/* ── 1 · Ink underline ────────────────────────────────────────────
   Applied to prose links. background-size animates on the compositor
   and leaves the text baseline alone, which text-decoration cannot. */
.ink-link,
.post-body a:not([class*="btn"]):not([class*="cta"]):not([class*="chip"]):not(.lang-pill):not(.back-link),
.coffee-post-body :not(.social-row) > a:not([class*="btn"]):not([class*="cta"]):not(.lang-pill):not(.back-link),
.legal-body a {
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 1px;
  padding-bottom: 1px;
  transition: background-size .34s cubic-bezier(.62,.02,.24,1), color .2s ease;
}
[dir="rtl"] .ink-link,
[dir="rtl"] .post-body a:not([class*="btn"]):not([class*="cta"]):not([class*="chip"]):not(.lang-pill):not(.back-link),
[dir="rtl"] .coffee-post-body :not(.social-row) > a:not([class*="btn"]):not([class*="cta"]):not(.lang-pill):not(.back-link),
[dir="rtl"] .legal-body a { background-position: 100% 100%; }
.ink-link:hover,
.post-body a:not([class*="btn"]):not([class*="cta"]):not([class*="chip"]):not(.lang-pill):not(.back-link):hover,
.coffee-post-body :not(.social-row) > a:not([class*="btn"]):not([class*="cta"]):not(.lang-pill):not(.back-link):hover,
.legal-body a:hover { background-size: 100% 2px; }
/* borders were the old underline; two underlines is one too many */
.legal-body a { border-block-end: 0; }

/* ── 2 · The nudge ────────────────────────────────────────────────
   An arrow at the end of a link leans forward on hover. 3px, once.
   Any more and it reads as a toy. */
.ink-go { display: inline-block; }
.ink-go::after {
  content: "\2192";
  display: inline-block;
  margin-inline-start: .4em;
  transition: transform .28s cubic-bezier(.62,.02,.24,1);
}
/* Hebrew CTAs carry no arrow at all (Tanya, Sept 1): the glyph kept
   landing on the wrong side and a direction cue that needs checking is
   not worth its pixels. */
[dir="rtl"] .ink-go::after { content: none; }
.ink-go:hover::after { transform: translateX(3px); }


/* ── 3 · Rules that wipe in ───────────────────────────────────────
   A section hairline draws from the start edge as the block arrives,
   so the sheet reads as being ruled rather than pre-printed. */
.ink-rule { position: relative; }
.ink-rule::after {
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: 0;
  block-size: 1px;
  inline-size: 0;
  background: var(--rule);
  transition: inline-size .9s cubic-bezier(.62,.02,.24,1);
}
.ink-rule.is-in::after { inline-size: 100%; }

/* ── 4 · Ticks ────────────────────────────────────────────────────
   Draws the check along its own length. The box is always present;
   only the mark is animated, because an appearing box reads as a
   layout shift. */
.ink-tick .nf-box,
.ink-tick .ink-box { fill: none; stroke: var(--rule); stroke-width: 5; }
.ink-tick .nf-tick,
.ink-tick .ink-check {
  fill: none;
  stroke: var(--accent);
  stroke-width: 7;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: var(--len, 90);
  stroke-dashoffset: var(--len, 90);
  transition: stroke-dashoffset .62s cubic-bezier(.62,.02,.24,1) .18s;
}
.ink-tick.is-in .nf-tick,
.ink-tick.is-in .ink-check { stroke-dashoffset: 0; }

/* ── 5 · Figures roll ─────────────────────────────────────────────
   Mono numerals only, and tabular, so nothing reflows while counting. */
.ink-num { font-variant-numeric: tabular-nums; }

/* ── Reduced motion: FINISHED, not disabled ──────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .ink-rule::after { inline-size: 100%; transition: none; }
  .ink-tick .nf-tick, .ink-tick .ink-check { stroke-dashoffset: 0; transition: none; }
  .ink-go::after, .ink-link { transition: none; }
}
html.a11y-motion .ink-rule::after { inline-size: 100%; transition: none; }
html.a11y-motion .ink-tick .nf-tick,
html.a11y-motion .ink-tick .ink-check { stroke-dashoffset: 0; transition: none; }

/* ══════════════════════════════════════════════════════════════════
   404 — the sheet with one box left unticked
   ══════════════════════════════════════════════════════════════════ */
.nf-entry { padding-block: clamp(2rem, 6vw, 5rem) 4rem; }
.nf-mark { margin-block-end: 1.6rem; }
.nf-mark svg { display: block; }
.nf-links { list-style: none; margin: 2.4rem 0 0; padding: 0; }
.nf-links li { border-block-start: 1px solid var(--rule); }
.nf-links li:last-child { border-block-end: 1px solid var(--rule); }
.nf-links a {
  display: grid;
  grid-template-columns: 3.4rem 1fr;
  gap: .1rem 1.2rem;
  align-items: baseline;
  padding: 1.05rem .2rem;
  text-decoration: none;
  color: var(--ink);
  transition: background .18s var(--ease, ease), color .18s var(--ease, ease);
}
.nf-links a:hover { background: var(--tint); }
.nf-k {
  grid-row: 1 / span 2;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .1em;
  color: var(--pencil);
  font-variant-numeric: tabular-nums;
}
.nf-t { font-family: var(--font-display); font-weight: 700; font-size: 1.12rem; letter-spacing: -.01em; }
.nf-links a:hover .nf-t { color: var(--accent); }
.nf-s { grid-column: 2; color: var(--sec); font-size: .94rem; line-height: 1.55; }
.nf-cta { margin-block-start: 2.4rem; }
@media (max-width: 620px) {
  .nf-links a { grid-template-columns: 1fr; gap: .25rem; }
  .nf-k { grid-row: auto; }
  .nf-s { grid-column: 1; }
}

/* ══════════════════════════════════════════════════════════════════
   6 · The design project's fill-in vocabulary (Sept 21, 2026)
   Ported from the Claude Design canvases' notebook.js. Markup opts in
   with [data-fx]; ink.js adds .is-in on arrival (after [data-delay]).
   Five verbs, all resolving to their finished state under reduced
   motion:
     rise   a block settles up into place
     tick   a checkbox fills, its mark pops in
     draw   a line draws along its own axis (transform: scaleX/scaleY)
     flag   a row's text turns accent, one after another
     count  a mono figure rolls up (behaviour in ink.js)
   ══════════════════════════════════════════════════════════════════ */
[data-fx="rise"] { opacity: 0; transform: translateY(10px); transition: opacity .6s cubic-bezier(.2,.8,.2,1), transform .6s cubic-bezier(.2,.8,.2,1); }
[data-fx="rise"].is-in { opacity: 1; transform: none; }

[data-fx="draw"] { transform: scaleX(0); transform-origin: left center; transition: transform .9s cubic-bezier(.2,.8,.2,1); }
[dir="rtl"] [data-fx="draw"] { transform-origin: right center; }
[data-fx="draw"][data-axis="y"] { transform: scaleY(0); transform-origin: top; }
[data-fx="draw"].is-in { transform: none; }

[data-fx="tick"] { transition: background-color .25s, border-color .25s; }
[data-fx="tick"] [data-mark] { opacity: 0; transform: scale(.4); transition: opacity .2s, transform .3s cubic-bezier(.2,1.5,.4,1); }
[data-fx="tick"].is-in { background: var(--accent); border-color: var(--accent); }
[data-fx="tick"].is-in [data-mark] { opacity: 1; transform: none; }

[data-fx="flag"] { transition: color .3s, background-color .3s; }
[data-fx="flag"].is-in { color: var(--accent); }

/* The hero's own keyframes: word entrance, the bouncy full stop, a line
   being written (clip-path in steps), a strike drawing through a word. */
@keyframes vlnWord { 0% { opacity: 0; transform: translateY(.55em) scaleY(1.12); } 100% { opacity: 1; transform: none; } }
@keyframes vlnDot { 0% { opacity: 0; transform: translateY(-.9em); } 55% { opacity: 1; transform: translateY(0) scale(1.35,.65); } 78% { transform: scale(.9,1.12); } 100% { opacity: 1; transform: none; } }
@keyframes vlnPulse { 0%, 92%, 100% { transform: scale(1); } 96% { transform: scale(1.3); } }
@keyframes vlnScaleX { to { transform: scaleX(1); } }
@keyframes vlnFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes vlnRevealR { from { clip-path: inset(-10% 0 -10% 100%); } to { clip-path: inset(-10% 0 -10% 0); } }
@keyframes vlnRevealL { from { clip-path: inset(-10% 100% -10% 0); } to { clip-path: inset(-10% 0 -10% 0); } }

@media (prefers-reduced-motion: reduce) {
  [data-fx="rise"], [data-fx="draw"], [data-fx="draw"][data-axis="y"] { opacity: 1; transform: none; transition: none; }
  [data-fx="tick"] { background: var(--accent); border-color: var(--accent); transition: none; }
  [data-fx="tick"] [data-mark] { opacity: 1; transform: none; transition: none; }
  [data-fx="flag"] { color: var(--accent); transition: none; }
  .vln-hero * { animation: none !important; opacity: 1 !important; transform: none !important; clip-path: none !important; visibility: visible !important; }
}
html.a11y-motion [data-fx="rise"], html.a11y-motion [data-fx="draw"] { opacity: 1; transform: none; transition: none; }
html.a11y-motion [data-fx="tick"] { background: var(--accent); border-color: var(--accent); transition: none; }
html.a11y-motion [data-fx="tick"] [data-mark] { opacity: 1; transform: none; transition: none; }
html.a11y-motion [data-fx="flag"] { color: var(--accent); transition: none; }
html.a11y-motion .vln-hero * { animation: none !important; opacity: 1 !important; transform: none !important; clip-path: none !important; visibility: visible !important; }
