diff --git a/README.md b/README.md index 836ad08..315c7ae 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,8 @@ publishes the lot over its own OPDS catalog — which doubles as a [BookOrbit](https://github.com/thallada/bookorbit) watched folder if you run one. Each article chapter ends with a one-line note of what the pipeline made of the piece (topic, format, depth, and the reader interests it matched) and Loved it / -Good / Not for me links that feed back into tomorrow's curation; a short *Behind +Good / Not for me / AI slop links that feed back into tomorrow's curation (an AI +slop report also cuts every future article by that author); a short *Behind the paper* chapter before the colophon says what the run considered, how the deep set was admitted, whether the learned signals were active, the ten highest-utility near misses, and what it all cost. @@ -125,7 +126,7 @@ is current. daily-epub generate [--date YYYY-MM-DD] [--dry-run] [--out DIR] [--max-articles N] [--skip-llm] [--skip-embeddings] [--rescore] daily-epub serve # public site, private dashboard, OPDS, ratings, downloads daily-epub profile rebuild # regenerate learned profile adjustments -daily-epub ratings list [--days 90] [--label loved|good|down|cleared] +daily-epub ratings list [--days 90] [--label loved|good|down|slop|cleared] daily-epub ratings set --article 42 --label loved --note "excellent" daily-epub ratings clear --url https://example.com/article daily-epub explain --date YYYY-MM-DD (--article ID | --url URL) [--run-id N] @@ -403,6 +404,7 @@ prints what resolved. | `curation.feedback.loved_value` | `1.0` | Weight for a Loved it verdict. | | `curation.feedback.good_value` | `0.35` | Weight for a Good verdict. | | `curation.feedback.not_for_me_value` | `-1.0` | Weight for a Not for me verdict. | +| `curation.feedback.slop_value` | `-1.0` | Weight for an AI slop verdict; the author penalty is `curation.ranking.slop_author_penalty`. | | `curation.feedback.verdicts_in_prompt` | `60` | Recent explicit verdicts included in the system prompt. | | `curation.recent_rejection_days` | `7` | Churn window for recent low triage/deep assessments. | | `curation.recent_rejection_floor` | `3.0` | Scores below this floor are excluded during the churn window (except auto-includes). | @@ -448,7 +450,10 @@ gated: `knn` (rated-neighbour preference) ramps from `knn_floor` (8) to `feed_floor` (15) to `feed_full` (40) attributable ratings; below the floor the signal is absent. Ratings decay with `rating_half_life_days` (60) over `rating_lookback_days` (180); `neighbour_k` (5) neighbours per side and -`negative_coefficient` (0.75) shape the signal. `triage_max` (800), +`negative_coefficient` (0.75) shape the signal. `slop_author_penalty` (0.75) +is the fraction of the blend and utility removed from every candidate whose +author currently carries an AI slop verdict, on any feed and with no age +limit. `triage_max` (800), `deep_keep` (120), `shortlist_keep` (60), `assessment_reuse_days` (3), `semantic_min_words` (300), `exploration_slots` (5), `[curation.ranking.quotas]` (`triage` 60 · `interest` 20 · `knn` 20), `[curation.ranking.weights.utility]` @@ -854,7 +859,7 @@ curl -s https://daily.hallada.net/healthz curl -s https://daily.hallada.net/opds/daily.xml | head curl -s https://daily.hallada.net/issues.json | jq '.[0]' -# 7. Feedback loop: tap Loved it / Good / Not for me in KOReader, then +# 7. Feedback loop: tap Loved it / Good / Not for me / AI slop in KOReader, then sqlite3 /var/lib/daily-epub/daily-epub.db 'select * from rating_events order by event_at desc;' # 8. Watch cost and quality for a week diff --git a/config.example.toml b/config.example.toml index 4ea0aa2..4469fc6 100644 --- a/config.example.toml +++ b/config.example.toml @@ -132,6 +132,7 @@ sections = [ loved_value = 1.0 good_value = 0.35 not_for_me_value = -1.0 +slop_value = -1.0 # AI slop: a full negative; the author penalty is below verdicts_in_prompt = 60 # Every weight, quota, gate and threshold of the personalized ranker. The @@ -150,6 +151,7 @@ knn_floor = 8 knn_full = 25 feed_floor = 15 feed_full = 40 +slop_author_penalty = 0.75 # blend and utility × 0.25 for authors with an AI slop verdict semantic_min_words = 300 exploration_slots = 5 embedding_retention_days = 120 # `features prune`: unrated, unpublished vectors diff --git a/src/config.rs b/src/config.rs index 5562ec9..072919e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -468,6 +468,10 @@ pub struct RankingConfig { pub knn_full: usize, pub feed_floor: usize, pub feed_full: usize, + /// Fraction of the preliminary blend and the utility removed from any + /// candidate whose author has a current *AI slop* verdict (§9.3). `1.0` + /// zeroes such candidates; `0.0` disables the penalty. + pub slop_author_penalty: f64, pub semantic_min_words: i64, pub exploration_slots: usize, pub embedding_retention_days: i64, @@ -492,6 +496,7 @@ impl Default for RankingConfig { knn_full: 25, feed_floor: 15, feed_full: 40, + slop_author_penalty: 0.75, semantic_min_words: 300, exploration_slots: 5, embedding_retention_days: 120, @@ -603,6 +608,9 @@ pub struct FeedbackConfig { pub loved_value: f64, pub good_value: f64, pub not_for_me_value: f64, + /// Weight of an *AI slop* verdict. The author penalty is separate + /// (`ranking.slop_author_penalty`). + pub slop_value: f64, pub verdicts_in_prompt: usize, } @@ -612,6 +620,7 @@ impl Default for FeedbackConfig { loved_value: 1.0, good_value: 0.35, not_for_me_value: -1.0, + slop_value: -1.0, verdicts_in_prompt: 60, } } @@ -1180,6 +1189,11 @@ impl Config { "curation.ranking *_full must be > *_floor >= 0".into(), )); } + if !(0.0..=1.0).contains(&ranking.slop_author_penalty) { + return Err(ConfigError::Invalid( + "curation.ranking.slop_author_penalty must be between 0 and 1".into(), + )); + } if !(0.0..=1.0).contains(&ranking.diversity.cluster_threshold) { return Err(ConfigError::Invalid( "curation.ranking.diversity.cluster_threshold must be between 0 and 1".into(), @@ -1438,6 +1452,8 @@ mod tests { assert_eq!(c.curation.recent_rejection_floor, 3.0); assert_eq!(c.profile_path, PathBuf::from("data/profile.md")); assert_eq!(c.curation.feedback.good_value, 0.35); + assert_eq!(c.curation.feedback.slop_value, -1.0); + assert_eq!(c.curation.ranking.slop_author_penalty, 0.75); assert_eq!(c.curation.feedback.verdicts_in_prompt, 60); assert_eq!(c.xtc.format, XtcFormat::Xtch); assert_eq!(c.curation.sections.len(), 8); diff --git a/src/curate/assess.rs b/src/curate/assess.rs index f0d7848..2e4dead 100644 --- a/src/curate/assess.rs +++ b/src/curate/assess.rs @@ -211,6 +211,7 @@ fn render_candidate(candidate: &Candidate) -> String { "loved" => "LOVED", "good" => "GOOD", "not_for_me" | "down" => "NOT FOR ME", + "slop" => "AI SLOP", other => other, }; format!("{label} \"{}\" ({:.2})", neighbour.title, neighbour.cos) diff --git a/src/curate/editor.rs b/src/curate/editor.rs index 112fe37..f18f28d 100644 --- a/src/curate/editor.rs +++ b/src/curate/editor.rs @@ -172,6 +172,7 @@ fn render_candidate(candidate: &Candidate) -> String { "loved" => "LOVED", "good" => "GOOD", "not_for_me" | "down" => "NOT FOR ME", + "slop" => "AI SLOP", other => other, }; format!("{label} \"{}\" ({:.2})", neighbour.title, neighbour.cos) diff --git a/src/curate/profile/mod.rs b/src/curate/profile/mod.rs index 38eda2c..3a05bf5 100644 --- a/src/curate/profile/mod.rs +++ b/src/curate/profile/mod.rs @@ -162,6 +162,7 @@ fn verdict_label(label: &str) -> &str { "loved" => "LOVED", "good" => "GOOD", "not_for_me" => "NOT FOR ME", + "slop" => "AI SLOP", other => other, } } diff --git a/src/curate/rank.rs b/src/curate/rank.rs index 4cec945..85452b2 100644 --- a/src/curate/rank.rs +++ b/src/curate/rank.rs @@ -13,7 +13,8 @@ pub struct RankSummary { pub clusters: usize, } -/// Re-normalize cheap signals over the deep set and calculate utility on 0–100. +/// Re-normalize cheap signals over the deep set and calculate utility on 0–100, +/// scaled by the slop-author factor (§9.3). pub fn calculate_utility(candidates: &mut [Candidate], configured: &UtilityWeights) { let indices = (0..candidates.len()).collect::>(); calculate_utility_for(candidates, &indices, configured); @@ -88,7 +89,8 @@ fn calculate_utility_for( .iter() .map(|(_, weight, value)| weight / total * value) .sum::() - * 100.0, + * 100.0 + * candidate.signals.slop_factor(), ); } } @@ -345,6 +347,23 @@ mod tests { ); } + #[test] + fn slop_authors_keep_their_weights_but_lose_most_of_their_utility() { + let mut reported = candidate(1, 8.0); + let mut other = candidate(2, 8.0); + reported.signals.slop_author = true; + reported.signals.slop_penalty = 0.75; + other.signals.slop_author = false; + other.signals.slop_penalty = 0.75; + let mut values = vec![reported, other]; + calculate_utility(&mut values, &UtilityWeights::default()); + let [reported, other] = values.as_slice() else { + panic!("two values") + }; + assert_eq!(reported.signals.weights, other.signals.weights); + assert!((reported.utility.unwrap() - other.utility.unwrap() * 0.25).abs() < 1e-9); + } + #[test] fn duplicates_cluster_and_the_third_is_suppressed() { let ranking = ranking(3, 0, 2, 0.85); diff --git a/src/curate/signals.rs b/src/curate/signals.rs index c40a41c..c17b22d 100644 --- a/src/curate/signals.rs +++ b/src/curate/signals.rs @@ -72,11 +72,29 @@ pub struct Signals { pub notes: Vec, /// Preliminary blend on a 0–100 scale; `None` when nothing is present. pub preliminary: Option, + /// The author has a current *AI slop* verdict (§9.3). + #[serde(default)] + pub slop_author: bool, /// Gate ramps applied to the learned signals' weights (§9.2, §9.3). #[serde(skip)] pub knn_gate: f64, #[serde(skip)] pub feed_gate: f64, + /// `ranking.slop_author_penalty`, applied when `slop_author` is set. + #[serde(skip)] + pub slop_penalty: f64, +} + +impl Signals { + /// The multiplier the slop-author penalty applies to the blend and the + /// utility: `1 − penalty` for a reported author, `1` otherwise (§9.3). + pub fn slop_factor(&self) -> f64 { + if self.slop_author { + (1.0 - self.slop_penalty).clamp(0.0, 1.0) + } else { + 1.0 + } + } } impl Signals { @@ -161,6 +179,9 @@ pub struct PreferenceState { pub examples: Vec, feed_rates: HashMap, author_rates: HashMap, + /// Normalized keys of authors with a current *AI slop* verdict (§9.3). + slop_authors: HashSet, + pub slop_author_penalty: f64, pub attributable_feed_ratings: usize, pub knn_gate: f64, pub feed_gate: f64, @@ -183,10 +204,36 @@ impl PreferenceState { examples, feed_rates, author_rates, + slop_authors: HashSet::new(), + slop_author_penalty: ranking.slop_author_penalty, attributable_feed_ratings, } } + /// Register the authors whose current verdict is *AI slop*; keys are + /// normalized like [`normalize_author`] and empty ones are dropped. + pub fn with_slop_authors(mut self, authors: I) -> Self + where + I: IntoIterator, + S: AsRef, + { + self.slop_authors = authors + .into_iter() + .filter_map(|author| normalize_author(Some(author.as_ref()))) + .collect(); + self + } + + /// Whether the article's author has a current *AI slop* verdict (§9.3). + pub fn is_slop_author(&self, article: &Article) -> bool { + normalize_author(article.author.as_deref()) + .is_some_and(|author| self.slop_authors.contains(&author)) + } + + pub fn slop_author_count(&self) -> usize { + self.slop_authors.len() + } + /// Load `db::current_ratings(rating_lookback_days)` joined to /// `article_embeddings`; ratings without an embedding are skipped (§9.2). pub async fn load( @@ -227,7 +274,8 @@ impl PreferenceState { aggregator_only, }); } - Ok(Self::build(examples, ranking)) + let slop_authors = db.slop_authors().await?; + Ok(Self::build(examples, ranking).with_slop_authors(slop_authors)) } pub fn summary(&self) -> PreferenceSummary { @@ -253,11 +301,14 @@ impl PreferenceState { rated_with_embeddings = self.examples.len(), knn_gate = self.knn_gate, feed_gate = self.feed_gate, - "preference: {} rated articles with embeddings → knn gate {:.2}; feed gate {:.1} {}", + slop_authors = self.slop_authors.len(), + "preference: {} rated articles with embeddings → knn gate {:.2}; feed gate {:.1} {}; {} slop authors (penalty {:.2})", self.examples.len(), self.knn_gate, self.feed_gate, - feed_detail + feed_detail, + self.slop_authors.len(), + self.slop_author_penalty ); } @@ -540,6 +591,14 @@ pub fn compute( signals.neighbours = neighbours; } signals.feed = preference.feed(article); + if preference.is_slop_author(article) { + signals.slop_author = true; + signals.slop_penalty = preference.slop_author_penalty; + signals.notes.push(format!( + "author reported as AI slop: blend and utility × {:.2}", + signals.slop_factor() + )); + } if preference.knn_gate > 0.0 { signals.notes.push(format!( "knn gate {:.2} (n={} rated with embeddings)", @@ -615,7 +674,8 @@ pub fn normalize(signals: &mut [&mut Signals]) { } /// The preliminary blend of §12.4 on a 0–100 scale: present-and-active -/// signals only, learned weights multiplied by their gate, renormalized to 1. +/// signals only, learned weights multiplied by their gate, renormalized to 1, +/// then scaled by the slop-author factor (§9.3). pub fn preliminary_blend(signals: &mut Signals, configured: &PreliminaryWeights) -> Option { let candidates = [ ("interest", configured.interest, 1.0), @@ -646,7 +706,8 @@ pub fn preliminary_blend(signals: &mut Signals, configured: &PreliminaryWeights) .iter() .map(|(_, weight, norm)| weight / total * norm) .sum::() - * 100.0; + * 100.0 + * signals.slop_factor(); signals.preliminary = Some(blend); Some(blend) } @@ -964,6 +1025,63 @@ mod tests { assert!((state.feed(&article(2, &[10])).unwrap() - 1.0 / 2.25).abs() < 1e-9); } + // --- §9.3 slop authors --- + + #[test] + fn slop_authors_are_normalized_and_scale_the_preliminary_blend() { + let state = PreferenceState::build(Vec::new(), &ranking()).with_slop_authors([ + " Content FARM ", + "", + " ", + ]); + assert_eq!(state.slop_author_count(), 1); + let mut reported = article(1, &[10]); + reported.author = Some("content farm".into()); + let mut other = article(2, &[10]); + other.author = Some("real writer".into()); + let anonymous = article(3, &[10]); + assert!(state.is_slop_author(&reported)); + assert!(!state.is_slop_author(&other)); + assert!(!state.is_slop_author(&anonymous)); + + let articles = vec![reported, other, anonymous]; + let computed = compute( + &articles, + &HashMap::new(), + &HashMap::new(), + &state, + &ranking(), + ); + let reported = &computed[&1]; + let other = &computed[&2]; + assert!(reported.slop_author); + assert!(!other.slop_author); + // Identical heuristic/social inputs: the only difference is the factor. + assert!((reported.preliminary.unwrap() - other.preliminary.unwrap() * 0.25).abs() < 1e-9); + assert!( + reported + .notes + .iter() + .any(|note| note.contains("author reported as AI slop")) + ); + assert!(!other.notes.iter().any(|note| note.contains("AI slop"))); + } + + #[test] + fn slop_factor_is_neutral_without_a_report_and_clamped_with_one() { + let mut signals = Signals { + slop_penalty: 0.75, + ..Signals::default() + }; + assert_eq!(signals.slop_factor(), 1.0); + signals.slop_author = true; + assert!((signals.slop_factor() - 0.25).abs() < 1e-9); + signals.slop_penalty = 1.0; + assert_eq!(signals.slop_factor(), 0.0); + signals.slop_penalty = 0.0; + assert_eq!(signals.slop_factor(), 1.0); + } + #[test] fn feed_is_absent_when_the_gate_is_closed() { let ranking = ranking(); // feed_floor 15 diff --git a/src/curate/telemetry.rs b/src/curate/telemetry.rs index 9e23e1d..f1685e3 100644 --- a/src/curate/telemetry.rs +++ b/src/curate/telemetry.rs @@ -129,6 +129,9 @@ pub struct SignalsJson { pub exploration: bool, #[serde(default)] pub auto_include: bool, + /// The author had a current *AI slop* verdict at run time (§9.3). + #[serde(default)] + pub slop_author: bool, #[serde(default)] pub notes: Vec, } @@ -177,6 +180,7 @@ pub fn serialize_signals(signals: &Signals, auto_include: bool) -> String { neighbours: signals.neighbours.clone(), exploration: false, auto_include, + slop_author: signals.slop_author, notes: signals.notes.clone(), }) .unwrap_or_else(|_| "{}".into()) @@ -400,11 +404,11 @@ pub async fn render_explain(db: &Db, row: &ExplainRow) -> Result String { "loved" => "LOVED", "good" => "GOOD", "not_for_me" | "down" => "NOT FOR ME", + "slop" => "AI SLOP", other => other, }; format!("{label} \"{}\" ({:.2})", neighbour.title, neighbour.cos) diff --git a/src/db.rs b/src/db.rs index 5254fac..39408a2 100644 --- a/src/db.rs +++ b/src/db.rs @@ -719,6 +719,33 @@ impl Db { self.latest_explicit_ratings(lookback_days, true).await } + /// Raw authors of every article whose current explicit verdict is `slop`, + /// regardless of age: a reported author stays penalized until the verdict is + /// changed or cleared (§9.3). Articles without an author contribute nothing. + pub async fn slop_authors(&self) -> Result> { + let rows = sqlx::query_scalar::<_, String>( + "WITH ranked AS ( + SELECT re.article_id, re.label, + ROW_NUMBER() OVER ( + PARTITION BY re.article_id + ORDER BY re.event_at DESC, re.id DESC + ) AS event_rank + FROM rating_events re + WHERE re.kind = 'explicit' + ) + SELECT DISTINCT COALESCE(a.author, e.author) AS author + FROM ranked r + JOIN articles a ON a.id = r.article_id + LEFT JOIN entries e ON e.id = a.best_entry_id + WHERE r.event_rank = 1 AND r.label = 'slop' + AND COALESCE(a.author, e.author) IS NOT NULL + ORDER BY author", + ) + .fetch_all(&self.pool) + .await?; + Ok(rows) + } + async fn latest_explicit_ratings( &self, lookback_days: i64, @@ -1551,6 +1578,67 @@ mod tests { assert_eq!(sources, ["cli", "cli", "bookorbit", "cli"]); } + #[tokio::test] + async fn slop_authors_follow_the_latest_verdict_and_fall_back_to_the_entry_author() { + let (_dir, db) = temp_db().await; + db.upsert_entry(&sample_entry(1)).await.unwrap(); + db.upsert_entry(&sample_entry(2)).await.unwrap(); + let mut page_author = Article { + id: 0, + canonical_url: "https://example.com/1".into(), + title: "Story 1".into(), + best_entry_id: 1, + content_html: "

body

".into(), + word_count: 900, + excerpt_only: false, + image_count: 0, + sources: vec![], + first_seen: ts("2026-08-15T05:30:00Z"), + url: "https://example.com/1".into(), + author: Some("Page Writer".into()), + feed_id: 7, + feed_title: "Hacker News".into(), + category: None, + published_at: None, + comments_url: None, + image_urls: vec![], + social: vec![], + extract_method: ExtractMethod::Miniflux, + }; + let first = db.upsert_article(&page_author).await.unwrap(); + page_author.canonical_url = "https://example.com/2".into(); + page_author.url = "https://example.com/2".into(); + page_author.best_entry_id = 2; + page_author.author = None; + let second = db.upsert_article(&page_author).await.unwrap(); + let event = |article_id: i64, label: &str, at: &str| RatingEvent { + id: 0, + user_id: None, + article_id, + issue_date: None, + kind: "explicit".into(), + source: "cli".into(), + label: label.into(), + value: -1.0, + note: None, + event_at: ts(at), + }; + assert!(db.slop_authors().await.unwrap().is_empty()); + // Ancient verdicts still count: there is no lookback. + db.append_rating_event(&event(first, "slop", "2020-01-01T00:00:00Z")) + .await + .unwrap(); + db.append_rating_event(&event(second, "slop", "2026-08-15T12:00:00Z")) + .await + .unwrap(); + assert_eq!(db.slop_authors().await.unwrap(), ["Page Writer", "someone"]); + // A later verdict on the same article replaces the slop one. + db.append_rating_event(&event(second, "cleared", "2026-08-15T13:00:00Z")) + .await + .unwrap(); + assert_eq!(db.slop_authors().await.unwrap(), ["Page Writer"]); + } + #[tokio::test] async fn curation_v2_migration_copies_ratings_and_drops_old_tables() { let pool = SqlitePoolOptions::new() diff --git a/src/epub/chapters.rs b/src/epub/chapters.rs index 1c58ca8..f50d76e 100644 --- a/src/epub/chapters.rs +++ b/src/epub/chapters.rs @@ -70,6 +70,7 @@ struct RatingLinks { loved_url: String, good_url: String, not_for_me_url: String, + slop_url: String, } #[derive(Template)] @@ -458,6 +459,7 @@ pub fn render_article( article.id, Vote::NotForMe, ), + slop_url: rating_url(public_url, secret, issue.meta.date, article.id, Vote::Slop), }), _ => None, }; diff --git a/src/epub/templates/chapter.xhtml b/src/epub/templates/chapter.xhtml index 35e85af..87eb42f 100644 --- a/src/epub/templates/chapter.xhtml +++ b/src/epub/templates/chapter.xhtml @@ -30,7 +30,7 @@

{{ line }}

{% endif %} {% if let Some(links) = rating %} -

Was this a good pick?   [ Loved it ]   [ Good ]   [ Not for me ]     Read online ↗

+

Was this a good pick?   [ Loved it ]   [ Good ]   [ Not for me ]   [ AI slop ]     Read online ↗

{% else %}

Read online ↗

{% endif %} diff --git a/src/imports.rs b/src/imports.rs index 18130e2..2811016 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -132,6 +132,7 @@ fn vote(label: &str) -> Result { "loved" => Ok(Vote::Loved), "good" => Ok(Vote::Good), "not_for_me" => Ok(Vote::NotForMe), + "slop" => Ok(Vote::Slop), other => anyhow::bail!("invalid rating label {other:?}"), } } diff --git a/src/main.rs b/src/main.rs index 5dce137..bc04c74 100644 --- a/src/main.rs +++ b/src/main.rs @@ -196,6 +196,7 @@ enum RatingListLabel { Loved, Good, Down, + Slop, Cleared, } @@ -205,6 +206,7 @@ impl RatingListLabel { Self::Loved => "loved", Self::Good => "good", Self::Down => "not_for_me", + Self::Slop => "slop", Self::Cleared => "cleared", } } @@ -215,6 +217,8 @@ enum RatingSetLabel { Loved, Good, Down, + /// AI slop: a full negative, and the author's future articles rank much lower. + Slop, } impl RatingSetLabel { @@ -223,6 +227,7 @@ impl RatingSetLabel { Self::Loved => Vote::Loved, Self::Good => Vote::Good, Self::Down => Vote::NotForMe, + Self::Slop => Vote::Slop, } } } diff --git a/src/rate.rs b/src/rate.rs index f6b465e..f97d008 100644 --- a/src/rate.rs +++ b/src/rate.rs @@ -1,5 +1,18 @@ //! Shared construction of explicit rating events. +/// The confirmation shown after an *AI slop* verdict: whether the author +/// penalty can apply depends on the article having an author at all (§9.3). +pub fn slop_message(author: Option<&str>) -> String { + match author.map(str::trim).filter(|author| !author.is_empty()) { + Some(author) => { + format!("Recorded: AI slop — thanks. Future articles by {author} will rank much lower.") + } + None => "Recorded: AI slop — thanks. This article has no known author, so only the \ + usual negative rating applies." + .to_string(), + } +} + use crate::config::Config; use crate::db::{Db, DbError}; use crate::types::{ArticleId, RatingEvent, Vote}; @@ -15,12 +28,7 @@ pub async fn record_explicit( note: Option, ) -> Result { let (label, value) = match vote { - Some(Vote::Loved) => ("loved", Vote::Loved.value(&config.curation.feedback)), - Some(Vote::Good) => ("good", Vote::Good.value(&config.curation.feedback)), - Some(Vote::NotForMe) => ( - "not_for_me", - Vote::NotForMe.value(&config.curation.feedback), - ), + Some(vote) => (vote.event_label(), vote.value(&config.curation.feedback)), None => ("cleared", 0.0), }; db.append_rating_event(&RatingEvent { diff --git a/src/server.rs b/src/server.rs index f1d9ae1..71541f3 100644 --- a/src/server.rs +++ b/src/server.rs @@ -377,11 +377,7 @@ async fn handle_rating( } }; - let label = match vote { - Vote::Loved => "loved", - Vote::Good => "good", - Vote::NotForMe => "not_for_me", - }; + let label = vote.event_label(); let event = RatingEvent { id: 0, user_id: None, @@ -408,11 +404,12 @@ async fn handle_rating( ); let message = match vote { - Vote::Loved => "Recorded: Loved it — thanks.", - Vote::Good => "Recorded: Good — thanks.", - Vote::NotForMe => "Recorded: Not for me — thanks.", + Vote::Loved => "Recorded: Loved it — thanks.".to_string(), + Vote::Good => "Recorded: Good — thanks.".to_string(), + Vote::NotForMe => "Recorded: Not for me — thanks.".to_string(), + Vote::Slop => crate::rate::slop_message(article.author.as_deref()), }; - confirmation_page(StatusCode::OK, message, &config, date, article_id, vote) + confirmation_page(StatusCode::OK, &message, &config, date, article_id, vote) } /// `GET /opds/daily.xml` — both EPUB editions of the last issues, newest first, @@ -644,23 +641,20 @@ fn confirmation_page( let Some(secret) = config.server.hmac_secret.as_deref() else { return page(status, message, None); }; - let choices = [ - (Vote::Loved, "Loved it"), - (Vote::Good, "Good"), - (Vote::NotForMe, "Not for me"), - ] - .into_iter() - .filter(|(vote, _)| *vote != selected) - .map(|(vote, label)| { - let url = rating_url(&config.server.public_url, secret, date, article_id, vote); - format!( - "[ {} ]", - escape_attr(&url), - escape(label) - ) - }) - .collect::>() - .join("   "); + let choices = [Vote::Loved, Vote::Good, Vote::NotForMe, Vote::Slop] + .into_iter() + .filter(|vote| *vote != selected) + .map(|vote| (vote, vote.display())) + .map(|(vote, label)| { + let url = rating_url(&config.server.public_url, secret, date, article_id, vote); + format!( + "[ {} ]", + escape_attr(&url), + escape(label) + ) + }) + .collect::>() + .join("   "); let issue_url = format!( "{}/issues/{date}", config.server.public_url.trim_end_matches('/') diff --git a/src/types.rs b/src/types.rs index 4bcd77a..dfae363 100644 --- a/src/types.rs +++ b/src/types.rs @@ -685,6 +685,10 @@ pub enum Vote { Good, #[serde(rename = "down")] NotForMe, + /// The article reads as AI-generated filler. A full negative, and every + /// later article by the same author is heavily penalized (§9.3). + #[serde(rename = "slop")] + Slop, } impl Vote { @@ -694,6 +698,27 @@ impl Vote { Vote::Loved => "loved", Vote::Good => "good", Vote::NotForMe => "down", + Vote::Slop => "slop", + } + } + + /// The `rating_events.label` this vote is stored under. + pub fn event_label(self) -> &'static str { + match self { + Vote::Loved => "loved", + Vote::Good => "good", + Vote::NotForMe => "not_for_me", + Vote::Slop => "slop", + } + } + + /// The reader-facing name of the verdict. + pub fn display(self) -> &'static str { + match self { + Vote::Loved => "Loved it", + Vote::Good => "Good", + Vote::NotForMe => "Not for me", + Vote::Slop => "AI slop", } } @@ -702,6 +727,7 @@ impl Vote { "loved" | "up" => Some(Vote::Loved), "good" => Some(Vote::Good), "down" => Some(Vote::NotForMe), + "slop" => Some(Vote::Slop), _ => None, } } @@ -711,6 +737,7 @@ impl Vote { Vote::Loved => cfg.loved_value, Vote::Good => cfg.good_value, Vote::NotForMe => cfg.not_for_me_value, + Vote::Slop => cfg.slop_value, } } } @@ -870,6 +897,12 @@ mod tests { assert_eq!(Vote::parse("up"), Some(Vote::Loved)); assert_eq!(Vote::parse("good"), Some(Vote::Good)); assert_eq!(Vote::parse("down"), Some(Vote::NotForMe)); + assert_eq!(Vote::parse("slop"), Some(Vote::Slop)); + assert_eq!(Vote::Slop.as_str(), "slop"); + assert_eq!(Vote::Slop.event_label(), "slop"); + assert_eq!(Vote::NotForMe.event_label(), "not_for_me"); + assert_eq!(Vote::Slop.value(&feedback), -1.0); + assert_eq!(serde_json::to_string(&Vote::Slop).unwrap(), "\"slop\""); assert_eq!(Vote::Loved.as_str(), "loved"); assert_eq!(Vote::Good.as_str(), "good"); assert_eq!(Vote::NotForMe.as_str(), "down"); diff --git a/src/web/dashboard/articles.rs b/src/web/dashboard/articles.rs index b7076ae..64fa54c 100644 --- a/src/web/dashboard/articles.rs +++ b/src/web/dashboard/articles.rs @@ -65,7 +65,7 @@ pub struct ArticlesQuery { pub page: Option, } -const RATED: [&str; 6] = ["any", "loved", "good", "down", "cleared", "none"]; +const RATED: [&str; 7] = ["any", "loved", "good", "down", "slop", "cleared", "none"]; const PUBLISHED: [&str; 2] = ["yes", "no"]; const ARTICLE_SORTS: [(&str, &str); 7] = [ @@ -152,7 +152,7 @@ impl ArticleFilters { match self.rated.as_deref() { Some("any") => sql.push_str(" AND x.rating IS NOT NULL AND x.rating != 'cleared'"), Some("none") => sql.push_str(" AND x.rating IS NULL"), - Some(label @ ("loved" | "good" | "cleared")) => { + Some(label @ ("loved" | "good" | "slop" | "cleared")) => { sql.push_str(" AND x.rating = ?"); binds.push(Bind::Text(label.to_string())); } diff --git a/src/web/dashboard/mod.rs b/src/web/dashboard/mod.rs index 0756472..43fcc5c 100644 --- a/src/web/dashboard/mod.rs +++ b/src/web/dashboard/mod.rs @@ -257,6 +257,7 @@ pub fn widget_label(label: Option<&str>) -> &'static str { Some("not_for_me" | "down") => "down", Some("loved") => "loved", Some("good") => "good", + Some("slop") => "slop", Some("cleared") => "cleared", _ => "", } @@ -297,6 +298,7 @@ pub struct SignalsView { pub neighbours: Vec, pub exploration: bool, pub auto_include: bool, + pub slop_author: bool, pub notes: Vec, /// A thin hygiene row (`{}`) or unparseable JSON: nothing to show. pub empty: bool, @@ -357,6 +359,7 @@ impl SignalsView { .collect(), exploration: signals.exploration, auto_include: signals.auto_include, + slop_author: signals.slop_author, notes: signals.notes.clone(), empty, } diff --git a/src/web/dashboard/ratings.rs b/src/web/dashboard/ratings.rs index ecd8881..5a5f4ed 100644 --- a/src/web/dashboard/ratings.rs +++ b/src/web/dashboard/ratings.rs @@ -244,6 +244,7 @@ fn event_label(widget: &str) -> Option<&'static str> { "loved" => Some("loved"), "good" => Some("good"), "down" => Some("not_for_me"), + "slop" => Some("slop"), "cleared" => Some("cleared"), _ => None, } @@ -255,6 +256,7 @@ fn widget_label(label: &str) -> (&'static str, &'static str) { "loved" => ("loved", "Loved it"), "good" => ("good", "Good"), "not_for_me" | "down" => ("down", "Not for me"), + "slop" => ("slop", "AI slop"), "cleared" => ("cleared", "Cleared"), _ => ("", "Unknown"), } @@ -412,6 +414,8 @@ struct HowValues { loved: String, good: String, not_for_me: String, + slop: String, + slop_author_penalty: String, verdicts_in_prompt: usize, rebuild_interval_days: i64, max_ratings_in_rebuild: usize, @@ -435,6 +439,8 @@ impl HowValues { loved: format!("{:+.2}", feedback.loved_value), good: format!("{:+.2}", feedback.good_value), not_for_me: format!("{:+.2}", feedback.not_for_me_value), + slop: format!("{:+.2}", feedback.slop_value), + slop_author_penalty: format!("{:.0}%", ranking.slop_author_penalty * 100.0), verdicts_in_prompt: feedback.verdicts_in_prompt, rebuild_interval_days: REBUILD_INTERVAL_DAYS, max_ratings_in_rebuild: MAX_RATINGS_IN_REBUILD, @@ -681,7 +687,7 @@ async fn queue_import( set_flash(&session, "error", message).await?; return Ok(Redirect::to("/dashboard/ratings#imports").into_response()); } - if !matches!(label.as_str(), "loved" | "good" | "not_for_me") { + if !matches!(label.as_str(), "loved" | "good" | "not_for_me" | "slop") { set_flash(&session, "error", "Choose a valid verdict.".into()).await?; return Ok(Redirect::to("/dashboard/ratings#imports").into_response()); } diff --git a/src/web/dashboard/settings.rs b/src/web/dashboard/settings.rs index 6b62260..712c754 100644 --- a/src/web/dashboard/settings.rs +++ b/src/web/dashboard/settings.rs @@ -334,6 +334,7 @@ pub const SETTINGS_HELP: &[(&str, &str)] = &[ ("curation.feedback.loved_value", "Weight for a Loved it verdict."), ("curation.feedback.good_value", "Weight for a Good verdict."), ("curation.feedback.not_for_me_value", "Weight for a Not for me verdict."), + ("curation.feedback.slop_value", "Weight for an AI slop verdict (the author penalty is separate)."), ("curation.feedback.verdicts_in_prompt", "Recent explicit verdicts included in the system prompt."), ("curation.ranking.triage_max", "Eligible articles the triage LLM reads."), ("curation.ranking.deep_keep", "Size of the deep-assessment set. Must be >= shortlist_keep."), @@ -343,6 +344,7 @@ pub const SETTINGS_HELP: &[(&str, &str)] = &[ ("curation.ranking.rating_half_life_days", "Ratings decay with this half-life."), ("curation.ranking.neighbour_k", "Rated neighbours per side for the knn signal."), ("curation.ranking.negative_coefficient", "How strongly Not for me neighbours pull a candidate down."), + ("curation.ranking.slop_author_penalty", "Fraction of the blend and utility removed from candidates whose author has a current AI slop verdict (0 disables, 1 zeroes)."), ("curation.ranking.knn_floor", "Rated articles with embeddings before the knn signal starts to count."), ("curation.ranking.knn_full", "Rated articles at which the knn signal reaches full weight. Must be > knn_floor."), ("curation.ranking.feed_floor", "Attributable ratings before the feed-affinity signal starts to count."), diff --git a/src/web/issue.rs b/src/web/issue.rs index baabfd3..1c3f752 100644 --- a/src/web/issue.rs +++ b/src/web/issue.rs @@ -2768,6 +2768,88 @@ mod tests { assert_eq!(down, "not_for_me"); } + #[tokio::test] + async fn slop_verdict_is_stored_under_its_own_label_and_names_the_author() { + let (_dir, db, source) = seeded_issue(true).await; + let article_id = source.lineup.picks[0].article.id; + sqlx::query("UPDATE articles SET author = ? WHERE id = ?") + .bind("Content Farm") + .bind(article_id) + .execute(db.pool()) + .await + .unwrap(); + crate::web::users::add(&db, "admin", "correct horse battery", true) + .await + .unwrap(); + let app = crate::server::router(crate::server::AppState::new( + db.clone(), + crate::config::Config::default(), + None, + )); + let admin_cookie = login_cookie(&app, "admin", "correct horse battery").await; + + let json = app + .clone() + .oneshot( + Request::builder() + .method(Method::POST) + .uri("/rate") + .header(header::COOKIE, &admin_cookie) + .header(header::CONTENT_TYPE, "application/json") + .header(header::ACCEPT, "application/json") + .header("sec-fetch-site", "same-origin") + .body(Body::from( + json!({"article_id": article_id, "label": "slop"}).to_string(), + )) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(json.status(), StatusCode::OK); + let body: serde_json::Value = serde_json::from_str(&response_text(json).await).unwrap(); + assert_eq!(body["label"], "slop"); + let stored = sqlx::query("SELECT label, value FROM rating_events ORDER BY id DESC LIMIT 1") + .fetch_one(db.pool()) + .await + .unwrap(); + assert_eq!(stored.get::("label"), "slop"); + assert_eq!(stored.get::("value"), -1.0); + assert_eq!(db.slop_authors().await.unwrap(), ["Content Farm"]); + + let redirected = app + .clone() + .oneshot( + Request::builder() + .method(Method::POST) + .uri("/rate") + .header(header::COOKIE, &admin_cookie) + .header(header::CONTENT_TYPE, "application/x-www-form-urlencoded") + .header("sec-fetch-site", "same-origin") + .body(Body::from(format!( + "article_id={article_id}&label=slop&next=%2Fissues%2F{}", + source.meta.date + ))) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(redirected.status(), StatusCode::SEE_OTHER); + let page = app + .oneshot( + Request::builder() + .uri(format!("/issues/{}", source.meta.date)) + .header(header::COOKIE, &admin_cookie) + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + let html = response_text(page).await; + assert!(html.contains("Future articles by Content Farm will rank much lower")); + assert!(html.contains(r#"data-label="slop" title="Report as AI slop"#)); + assert!(html.contains(r#"value="slop" data-label="slop" title="Report as AI slop: a strong Not for me, and future articles by this author rank much lower" class="active" aria-pressed="true""#)); + } + #[tokio::test] async fn toc_numbers_chapters_across_sections_and_tracks_the_reader() { let (_dir, db, source) = seeded_issue(true).await; diff --git a/src/web/rate.rs b/src/web/rate.rs index c2d734e..fc7b417 100644 --- a/src/web/rate.rs +++ b/src/web/rate.rs @@ -45,6 +45,7 @@ fn web_label(label: Option<&str>) -> &str { Some("not_for_me" | "down") => "down", Some("loved") => "loved", Some("good") => "good", + Some("slop") => "slop", Some("cleared") => "cleared", _ => "", } @@ -122,12 +123,12 @@ pub async fn post( let viewer = auth.user().await.ok_or_else(|| WebError::Unauthenticated { next: "/rate".into(), })?; - if state.db.get_article(input.article_id).await?.is_none() { + let Some(article) = state.db.get_article(input.article_id).await? else { return Err(WebError::BadRequest(format!( "article {} does not exist", input.article_id ))); - } + }; let issue_date = match input .issue_date @@ -147,27 +148,24 @@ pub async fn post( } }; let config = state.config(); - let (event_label, value, response_label, flash_label) = match input.label.as_str() { - "loved" => ( - "loved", - Vote::Loved.value(&config.curation.feedback), - "loved", - "Loved it", + let (event_label, value, response_label, flash_text) = match input.label.as_str() { + "cleared" => ("cleared", 0.0, "cleared", "Rated: Cleared".to_string()), + "slop" => ( + "slop", + Vote::Slop.value(&config.curation.feedback), + "slop", + crate::rate::slop_message(article.author.as_deref()), ), - "good" => ( - "good", - Vote::Good.value(&config.curation.feedback), - "good", - "Good", - ), - "down" => ( - "not_for_me", - Vote::NotForMe.value(&config.curation.feedback), - "down", - "Not for me", - ), - "cleared" => ("cleared", 0.0, "cleared", "Cleared"), - _ => return Err(WebError::BadRequest("invalid rating label".into())), + widget => { + let vote = Vote::parse(widget) + .ok_or_else(|| WebError::BadRequest("invalid rating label".into()))?; + ( + vote.event_label(), + vote.value(&config.curation.feedback), + vote.as_str(), + format!("Rated: {}", vote.display()), + ) + } }; let note = input .note @@ -207,7 +205,7 @@ pub async fn post( "flash", Flash { kind: "success".into(), - text: format!("Rated: {flash_label}"), + text: flash_text, }, ) .await @@ -223,6 +221,7 @@ mod tests { #[test] fn database_and_widget_labels_are_mapped_explicitly() { assert_eq!(web_label(Some("not_for_me")), "down"); + assert_eq!(web_label(Some("slop")), "slop"); assert_eq!(web_label(Some("cleared")), "cleared"); assert_eq!(web_label(None), ""); } diff --git a/src/web/static/app.css b/src/web/static/app.css index 9f2ef57..0b36e9e 100644 --- a/src/web/static/app.css +++ b/src/web/static/app.css @@ -1,2 +1,2 @@ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--font-serif:"Newsreader", "Newsreader Fallback Georgia", "Newsreader Fallback Times", "Newsreader Fallback Noto Serif", "Newsreader Fallback DejaVu Serif", "Iowan Old Style", "Palatino Linotype", Georgia, serif;--font-mono:ui-monospace, SFMono-Regular, Menlo, monospace;--spacing:.25rem;--container-md:28rem;--container-lg:32rem;--container-2xl:42rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--tracking-normal:0em;--leading-tight:1.25;--leading-snug:1.375;--leading-normal:1.5;--leading-relaxed:1.625;--radius-sm:.25rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--default-mono-font-family:ui-monospace, SFMono-Regular, Menlo, monospace;--color-paper:var(--paper);--color-paper-2:var(--paper-2);--color-ink:var(--ink)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])),[hidden]{display:none!important}html{background-color:var(--paper);color:var(--ink);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{background-color:var(--paper);--tw-leading:1.65;min-height:100vh;color:var(--ink);font-optical-sizing:auto;margin:0;font-family:Newsreader,Newsreader Fallback Georgia,Newsreader Fallback Times,Newsreader Fallback Noto Serif,Newsreader Fallback DejaVu Serif,Iowan Old Style,Palatino Linotype,Georgia,serif;font-size:1.0625rem;line-height:1.65}::selection{background:var(--accent)}@supports (color:color-mix(in lab, red, red)){::selection{background:color-mix(in oklab, var(--accent) 24%, transparent)}}a{color:var(--accent);-webkit-text-decoration-color:var(--rule);-webkit-text-decoration-color:var(--rule);text-decoration-color:var(--rule);text-underline-offset:4px;transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}@media (hover:hover){a:hover{color:var(--accent-hover)}}a:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--accent);--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-offset-color:var(--paper);--tw-outline-style:none;outline-style:none}h1,h2,h3{color:var(--ink);font-optical-sizing:auto}button,input,select,textarea{font:inherit;border-radius:var(--radius-sm);border-style:var(--tw-border-style);border-width:1px;border-color:var(--rule);background-color:var(--paper);padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * 1.5);color:var(--ink);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}:is(button,input,select,textarea)::placeholder{color:var(--muted)}:is(button,input,select,textarea):focus{border-color:var(--ink);--tw-outline-style:none;outline-style:none}:is(button,input,select,textarea):focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--accent);--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-offset-color:var(--paper)}button{cursor:pointer}button:disabled,input:disabled,select:disabled,textarea:disabled{cursor:not-allowed;border-color:var(--rule);background-color:var(--paper-2);color:var(--muted)}textarea{min-height:calc(var(--spacing) * 28)}summary{cursor:pointer}table{border-collapse:collapse;width:100%;font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-snug);line-height:var(--leading-snug);font-variant-numeric:tabular-nums}thead{z-index:10;background-color:var(--paper);position:sticky;top:0}th,td{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--rule);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 2);text-align:left;vertical-align:top}th{--tw-font-weight:var(--font-weight-semibold);font-size:.72rem;font-weight:var(--font-weight-semibold);--tw-tracking:.1em;letter-spacing:.1em;color:var(--muted);text-transform:uppercase}tbody tr{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}@media (hover:hover){tbody tr:hover{background-color:var(--paper-2)}}code,pre{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}meter{height:calc(var(--spacing) * 2);border-radius:var(--radius-sm);appearance:none;background:var(--rule);width:100%;display:block}meter::-webkit-meter-bar{background:var(--rule);border:0;border-radius:2px;height:.5rem}meter::-webkit-meter-optimum-value{background:var(--good);border-radius:2px}meter::-webkit-meter-suboptimum-value{background:var(--good);border-radius:2px}meter::-webkit-meter-even-less-good-value{background:var(--good);border-radius:2px}meter.over::-webkit-meter-optimum-value{background:var(--down)}meter.over::-webkit-meter-suboptimum-value{background:var(--down)}meter.over::-webkit-meter-even-less-good-value{background:var(--down)}meter::-moz-meter-bar{background:var(--good);border-radius:2px}meter.over::-moz-meter-bar{background:var(--down)}@media (prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition-duration:.01ms!important}}}@layer components{.btn,.button{min-height:calc(var(--spacing) * 10);border-radius:var(--radius-sm);border-style:var(--tw-border-style);border-width:1px;border-color:var(--rule-strong);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--ink);--tw-duration:.15s;background-color:#0000;justify-content:center;align-items:center;text-decoration-line:none;transition-duration:.15s;display:inline-flex}@media (hover:hover){:is(.btn,.button):hover{background-color:var(--ink);color:var(--paper)}}:is(.btn,.button):focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--accent);--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-offset-color:var(--paper);--tw-outline-style:none;outline-style:none}.btn,.button{transition-property:transform,background-color,color,border-color}.btn-primary{min-height:calc(var(--spacing) * 10);border-radius:var(--radius-sm);border-style:var(--tw-border-style);border-width:1px;border-color:var(--ink);background-color:var(--ink);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--paper);--tw-duration:.15s;justify-content:center;align-items:center;text-decoration-line:none;transition-duration:.15s;display:inline-flex}@media (hover:hover){.btn-primary:hover{border-color:var(--accent);background-color:var(--accent);color:var(--paper)}}.btn-primary:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--accent);--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-offset-color:var(--paper);--tw-outline-style:none;outline-style:none}.btn-primary{transition-property:transform,background-color,color,border-color}.btn-quiet{min-height:calc(var(--spacing) * 9);align-items:center;gap:var(--spacing);border-radius:var(--radius-sm);border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 2);padding-block:var(--spacing);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted);text-decoration-line:underline;-webkit-text-decoration-color:var(--rule);-webkit-text-decoration-color:var(--rule);text-decoration-color:var(--rule);text-underline-offset:4px;background-color:#0000;border-width:0;display:inline-flex}@media (hover:hover){.btn-quiet:hover{color:var(--ink);-webkit-text-decoration-color:var(--accent);-webkit-text-decoration-color:var(--accent);text-decoration-color:var(--accent)}}.btn:disabled,.btn-primary:disabled,.btn-danger:disabled{cursor:not-allowed;border-color:var(--rule);background-color:var(--paper-2);color:var(--muted)}@media (hover:hover){:is(.btn:disabled,.btn-primary:disabled,.btn-danger:disabled):hover{background-color:var(--paper-2);color:var(--muted)}}.btn-danger,button.danger{min-height:calc(var(--spacing) * 9);border-radius:var(--radius-sm);border-style:var(--tw-border-style);border-width:1px;border-color:var(--down);padding-inline:calc(var(--spacing) * 2.5);padding-block:var(--spacing);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--down);--tw-duration:.15s;background-color:#0000;justify-content:center;align-items:center;transition-duration:.15s;display:inline-flex}@media (hover:hover){:is(.btn-danger,button.danger):hover{background-color:var(--down);color:var(--paper)}}.btn-danger,button.danger{transition-property:transform,background-color,color,border-color}.btn:active,.button:active,.btn-primary:active,.btn-danger:active,button.danger:active{transform:scale(.96)}.badge{padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * .5);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);white-space:nowrap;--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);color:var(--ink-2);background:var(--ink);border-radius:3.40282e38px;align-items:center;display:inline-flex}@supports (color:color-mix(in lab, red, red)){.badge{background:color-mix(in oklab, var(--ink) 8%, transparent)}}.badge.selected,.badge.loved,.badge.ok{color:var(--loved);background:var(--loved)}@supports (color:color-mix(in lab, red, red)){.badge.selected,.badge.loved,.badge.ok{background:color-mix(in oklab, var(--loved) 14%, transparent)}}.badge.good,.badge.assessed,.badge.triaged,.badge.degraded{color:var(--good);background:var(--good)}@supports (color:color-mix(in lab, red, red)){.badge.good,.badge.assessed,.badge.triaged,.badge.degraded{background:color-mix(in oklab, var(--good) 14%, transparent)}}.badge.down,.badge.excluded,.badge.failed,.badge.dry_run{color:var(--down);background:var(--down)}@supports (color:color-mix(in lab, red, red)){.badge.down,.badge.excluded,.badge.failed,.badge.dry_run{background:color-mix(in oklab, var(--down) 14%, transparent)}}.badge.shortlisted,.badge.admitted,.badge.eligible,.badge.cleared,.badge.reason,.badge.running,.badge.requested{color:var(--muted);background:var(--muted)}@supports (color:color-mix(in lab, red, red)){.badge.shortlisted,.badge.admitted,.badge.eligible,.badge.cleared,.badge.reason,.badge.running,.badge.requested{background:color-mix(in oklab, var(--muted) 14%, transparent)}}.badge.restart,.badge.warn{color:var(--warn);background:var(--warn)}@supports (color:color-mix(in lab, red, red)){.badge.restart,.badge.warn{background:color-mix(in oklab, var(--warn) 16%, transparent)}}.kv{column-gap:calc(var(--spacing) * 5);row-gap:calc(var(--spacing) * 1.5);grid-template-columns:minmax(9rem,1fr) 2fr;display:grid}.kv dt{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted)}.kv dd{min-width:0;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));overflow-wrap:anywhere;margin:0}.scroll-x{overscroll-behavior-inline:contain;max-width:100%;overflow-x:auto}.scroll-x>table{min-width:max-content}.scroll-x.tall{overscroll-behavior-block:contain;max-height:70vh;overflow-y:auto}.reader-page{overflow-wrap:anywhere;min-width:0}.prose-body{--tw-leading:1.72;color:var(--ink);font-size:1.0625rem;line-height:1.72}.prose-body>*+*{margin-top:calc(var(--spacing) * 5)}.prose-body p,.index-summary{text-wrap:pretty}.prose-body h2{margin-top:calc(var(--spacing) * 10);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--rule);padding-top:calc(var(--spacing) * 4);font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height));--tw-leading:1.1;--tw-font-weight:var(--font-weight-semibold);line-height:1.1;font-weight:var(--font-weight-semibold);--tw-tracking:-.01em;letter-spacing:-.01em}.prose-body h3{margin-top:calc(var(--spacing) * 8);font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height));--tw-leading:1.15;--tw-font-weight:var(--font-weight-semibold);line-height:1.15;font-weight:var(--font-weight-semibold);--tw-tracking:-.01em;letter-spacing:-.01em}.prose-body a{color:var(--ink);text-decoration-line:underline;-webkit-text-decoration-color:var(--rule);-webkit-text-decoration-color:var(--rule);text-decoration-color:var(--rule);text-underline-offset:4px}@media (hover:hover){.prose-body a:hover{color:var(--ink);-webkit-text-decoration-color:var(--accent);-webkit-text-decoration-color:var(--accent);text-decoration-color:var(--accent)}}.prose-body img{margin-inline:auto;margin-block:calc(var(--spacing) * 7);border-radius:var(--radius-sm);text-align:center;max-width:100%;height:auto;font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted);outline-offset:-1px;outline:1px solid oklch(0% 0 0/.1);font-style:italic;display:block}@media (prefers-color-scheme:dark){:root:not([data-theme=light]) .prose-body img{outline-color:oklch(100% 0 0/.1)}}:root[data-theme=dark] .prose-body img{outline-color:oklch(100% 0 0/.1)}.prose-body table{overscroll-behavior-inline:contain;max-width:100%;display:block;overflow-x:auto}.prose-body th,.prose-body td{overflow-wrap:normal}.prose-body pre{border-radius:var(--radius-sm);background-color:var(--paper-2);max-width:100%;padding:calc(var(--spacing) * 4);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);overflow-x:auto}.prose-body :not(pre)>code{border-radius:var(--radius-sm);background-color:var(--paper-2);padding-inline:var(--spacing);padding-block:calc(var(--spacing) * .5);font-size:.9em}.prose-body blockquote{margin-block:calc(var(--spacing) * 7);border-left-style:var(--tw-border-style);border-left-width:2px;border-color:var(--rule-strong);padding-left:calc(var(--spacing) * 5);color:var(--ink-2)}.prose-body ul{padding-left:calc(var(--spacing) * 6);list-style-type:disc}.prose-body ol{padding-left:calc(var(--spacing) * 6);list-style-type:decimal}.prose-body li::marker{color:var(--muted)}.prose-body li+li{margin-top:calc(var(--spacing) * 2)}.reader-page :where(h1,h2,h3,h4),.reader-section-heading{text-wrap:balance}.reader-section-heading{border-top-style:var(--tw-border-style);--tw-border-style:double;border-style:double;border-top-width:3px;border-color:var(--rule-strong);padding-top:calc(var(--spacing) * 3);--tw-leading:1.2;--tw-font-weight:var(--font-weight-semibold);font-family:Newsreader,Newsreader Fallback Georgia,Newsreader Fallback Times,Newsreader Fallback Noto Serif,Newsreader Fallback DejaVu Serif,Iowan Old Style,Palatino Linotype,Georgia,serif;font-size:1.05rem;line-height:1.2;font-weight:var(--font-weight-semibold);--tw-tracking:.15em;letter-spacing:.15em;color:var(--ink);text-transform:uppercase}.rating{margin-block:calc(var(--spacing) * 5);align-items:center;column-gap:calc(var(--spacing) * 3);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));flex-wrap:wrap;display:flex}.rating-prompt{color:var(--muted);font-family:Newsreader,Newsreader Fallback Georgia,Newsreader Fallback Times,Newsreader Fallback Noto Serif,Newsreader Fallback DejaVu Serif,Iowan Old Style,Palatino Linotype,Georgia,serif;font-size:.8rem;font-style:italic}.rating-actions{min-height:calc(var(--spacing) * 10);white-space:nowrap;align-items:center;display:flex}.rating button[data-label]{height:calc(var(--spacing) * 8);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-duration:.15s;transition-property:transform,background-color,color,border-color;transition-duration:.15s;position:relative}.rating button[data-label]:after{content:"";inset-inline:0;inset-block:calc(var(--spacing) * -1.5);position:absolute}.rating button[data-label]:active{transform:scale(.96)}.rating button[data-label]:focus-visible{z-index:20;--tw-ring-offset-width:0px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.rating button[data-label]:not(.clear){border-color:var(--rule);padding-inline:calc(var(--spacing) * 2);padding-block:var(--spacing);color:var(--ink-2);background-color:#0000;border-radius:0;margin-left:-1px}.rating button[data-label]:not(.clear):first-child{border-top-left-radius:var(--radius-sm);border-bottom-left-radius:var(--radius-sm);margin-left:0}.rating button[data-label]:not(.clear):last-child{border-top-right-radius:var(--radius-sm);border-bottom-right-radius:var(--radius-sm)}@media (hover:hover){.rating button[data-label]:not(.clear):hover{z-index:10;border-color:var(--ink);background-color:var(--paper-2);color:var(--ink)}}.rating button.active[data-label=loved]{z-index:10;border-color:var(--loved);color:var(--loved);background:var(--loved)}@supports (color:color-mix(in lab, red, red)){.rating button.active[data-label=loved]{background:color-mix(in oklab, var(--loved) 14%, transparent)}}.rating button.active[data-label=good]{z-index:10;border-color:var(--good);color:var(--good);background:var(--good)}@supports (color:color-mix(in lab, red, red)){.rating button.active[data-label=good]{background:color-mix(in oklab, var(--good) 14%, transparent)}}.rating button.active[data-label=down]{z-index:10;border-color:var(--down);color:var(--down);background:var(--down)}@supports (color:color-mix(in lab, red, red)){.rating button.active[data-label=down]{background:color-mix(in oklab, var(--down) 14%, transparent)}}.rating button.clear{visibility:hidden;margin-left:calc(var(--spacing) * 1.5);border-style:var(--tw-border-style);padding-inline:var(--spacing);color:var(--muted);text-decoration-line:underline;-webkit-text-decoration-color:var(--rule);-webkit-text-decoration-color:var(--rule);text-decoration-color:var(--rule);text-underline-offset:4px;background-color:#0000;border-width:0}@media (hover:hover){.rating button.clear:hover{color:var(--ink)}}.rating:has(button[data-label]:not(.clear).active) button.clear,.rating button.clear.active{visibility:visible}.rating button.clear.active{text-decoration-line:none}.rating-cleared-label,.rating button.clear.active .rating-clear-label{display:none}.rating button.clear.active .rating-cleared-label{display:inline}.rating-note{margin-top:calc(var(--spacing) * 2);width:100%;max-width:var(--container-md);align-items:center;gap:calc(var(--spacing) * 2);color:var(--muted);flex-basis:100%;font-size:.72rem;display:flex}.rating-note input{border-inline-style:var(--tw-border-style);border-inline-width:0;border-top-style:var(--tw-border-style);border-top-width:0;border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--rule);min-width:0;padding-inline:0;padding-block:var(--spacing);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);background-color:#0000;border-radius:0;flex:1}.rating-note input:focus{border-color:var(--ink)}.flash{margin-block:calc(var(--spacing) * 4);border-left-style:var(--tw-border-style);border-left-width:4px;border-color:var(--accent);background-color:var(--paper-2);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.error{border-left-style:var(--tw-border-style);border-left-width:4px;border-color:var(--down);background-color:var(--paper-2);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--down)}.notice{border-left-style:var(--tw-border-style);border-left-width:4px;border-color:var(--warn);background-color:var(--paper-2);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--ink-2)}ul.error,ul.notice{padding-left:calc(var(--spacing) * 8);list-style-type:disc}.dashboard{margin-inline:auto;margin-block:calc(var(--spacing) * 8);max-width:var(--container-7xl);padding-inline:calc(var(--spacing) * 4);padding-bottom:calc(var(--spacing) * 6);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-leading:var(--leading-normal);line-height:var(--leading-normal)}@media (min-width:40rem){.dashboard{padding-inline:calc(var(--spacing) * 6)}}.dashboard>*+*{margin-top:calc(var(--spacing) * 4)}.dashboard h1{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height));--tw-leading:var(--leading-tight);line-height:var(--leading-tight);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:-.01em;letter-spacing:-.01em}.dashboard h2{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.dashboard h3{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.dashboard>h2{margin-top:calc(var(--spacing) * 9);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--rule);padding-top:calc(var(--spacing) * 3);--tw-font-weight:var(--font-weight-semibold);font-size:.78rem;font-weight:var(--font-weight-semibold);--tw-tracking:.14em;letter-spacing:.14em;color:var(--muted);text-transform:uppercase}.dashboard>p,.dashboard>ul,.dashboard>ol{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.dashboard code{border-radius:var(--radius-sm);background-color:var(--paper-2);padding-inline:var(--spacing);padding-block:calc(var(--spacing) * .5);font-size:.85em}.dashboard pre code{background-color:#0000;padding:0}.dashboard table a{color:var(--ink);text-decoration-line:underline;-webkit-text-decoration-color:var(--rule);-webkit-text-decoration-color:var(--rule);text-decoration-color:var(--rule);text-underline-offset:2px}@media (hover:hover){.dashboard table a:hover{color:var(--ink);-webkit-text-decoration-color:var(--accent);-webkit-text-decoration-color:var(--accent);text-decoration-color:var(--accent)}}.page-head{justify-content:space-between;align-items:flex-end;column-gap:calc(var(--spacing) * 6);row-gap:calc(var(--spacing) * 3);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--rule);padding-bottom:calc(var(--spacing) * 4);flex-wrap:wrap;display:flex}.page-head>div:first-child{min-width:0}.dashboard>.page-head+*{margin-top:calc(var(--spacing) * 6)}.page-desc{margin-top:calc(var(--spacing) * 1.5);max-width:74ch;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted)}.page-desc a{color:var(--accent)}.page-actions{align-items:center;gap:calc(var(--spacing) * 2);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));flex-wrap:wrap;display:flex}.page-eyebrow{--tw-tracking:.14em;letter-spacing:.14em;color:var(--muted);text-transform:uppercase;font-size:.7rem}.tiles{gap:calc(var(--spacing) * 3);grid-template-columns:repeat(auto-fit,minmax(min(10.5rem,100%),1fr));display:grid}.tile{border-style:var(--tw-border-style);border-width:1px;border-color:var(--rule);min-width:0;padding-inline:calc(var(--spacing) * 3.5);padding-block:calc(var(--spacing) * 3)}.tile-label{--tw-font-weight:var(--font-weight-medium);font-size:.68rem;font-weight:var(--font-weight-medium);--tw-tracking:.12em;letter-spacing:.12em;color:var(--muted);text-transform:uppercase;display:block}.tile-num{margin-top:var(--spacing);--tw-leading:var(--leading-tight);font-size:1.55rem;line-height:var(--leading-tight);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:-.01em;letter-spacing:-.01em;font-variant-numeric:tabular-nums;overflow-wrap:anywhere;display:block}.tile-delta{margin-top:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted);overflow-wrap:anywhere;display:block}.cards{gap:calc(var(--spacing) * 4);grid-template-columns:repeat(auto-fit,minmax(min(20rem,100%),1fr));display:grid}.card{border-style:var(--tw-border-style);border-width:1px;border-color:var(--rule);min-width:0;padding:calc(var(--spacing) * 4)}.card>*+*{margin-top:calc(var(--spacing) * 3)}.card h2,.card h3{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.card>h2:first-child,.card>h3:first-child{margin-top:0}.card p,.card li{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.muted,.meta{color:var(--muted)}.jobs a,.picks>li>a:first-child{color:var(--ink);text-decoration-line:none}@media (hover:hover){:is(.jobs a,.picks>li>a:first-child):hover{color:var(--accent)}}.num{text-align:right;white-space:nowrap;--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.cell-wrap{white-space:normal;overflow-wrap:anywhere;min-width:10rem;max-width:24rem}.cell-tight{white-space:nowrap}.filters{align-items:flex-end;column-gap:calc(var(--spacing) * 4);row-gap:calc(var(--spacing) * 3);border-block-style:var(--tw-border-style);border-block-width:1px;border-color:var(--rule);padding-block:calc(var(--spacing) * 3);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));flex-wrap:wrap;display:flex}.filters label{gap:var(--spacing);--tw-font-weight:var(--font-weight-medium);font-size:.66rem;font-weight:var(--font-weight-medium);--tw-tracking:.1em;letter-spacing:.1em;color:var(--muted);text-transform:uppercase;display:grid}.filters input,.filters select,.filters textarea{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal);color:var(--ink);text-transform:none}.filters select,.filters input[type=date]{min-width:calc(var(--spacing) * 32)}.filters .filter-actions{align-items:center;gap:calc(var(--spacing) * 3);display:flex}.form-inline{align-items:center;gap:calc(var(--spacing) * 3);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));flex-wrap:wrap;display:flex}.form-inline label{align-items:center;gap:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:flex}.table-filter{margin-block:calc(var(--spacing) * 2);width:calc(var(--spacing) * 80);max-width:100%;font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:none}.has-js .table-filter{display:block}[data-theme-icon],[data-theme-label]{display:none}html:not([data-theme]) [data-theme-icon=system],html[data-theme=light] [data-theme-icon=light],html[data-theme=dark] [data-theme-icon=dark]{display:block}html:not([data-theme]) [data-theme-label=system],html[data-theme=light] [data-theme-label=light],html[data-theme=dark] [data-theme-label=dark]{display:inline}.pager{justify-content:space-between;align-items:center;column-gap:calc(var(--spacing) * 6);row-gap:calc(var(--spacing) * 2);padding-block:var(--spacing);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted);--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);flex-wrap:wrap;display:flex}.pager a{color:var(--ink);text-decoration-line:none}@media (hover:hover){.pager a:hover{color:var(--accent)}}.run-nav{justify-content:space-between;align-items:center;column-gap:calc(var(--spacing) * 6);row-gap:calc(var(--spacing) * 2);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));flex-wrap:wrap;display:flex}.run-nav a{color:var(--ink);text-decoration-line:none}@media (hover:hover){.run-nav a:hover{color:var(--accent)}}.tabs{align-items:center;column-gap:calc(var(--spacing) * 6);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--rule);--tw-font-weight:var(--font-weight-medium);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:.72rem;font-weight:var(--font-weight-medium);--tw-tracking:.12em;letter-spacing:.12em;text-transform:uppercase;flex-wrap:wrap;display:flex}.tabs a{min-height:calc(var(--spacing) * 10);border-bottom-style:var(--tw-border-style);color:var(--muted);border-color:#0000;border-bottom-width:2px;align-items:center;margin-bottom:-1px;text-decoration-line:none;display:flex}@media (hover:hover){.tabs a:hover{color:var(--ink)}}.tabs a.active{border-color:var(--accent);color:var(--ink)}.pagination{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted);--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}tr.superseded>td,tr.superseded a{color:var(--muted)}td .rating,.picks .rating{row-gap:var(--spacing);max-width:none;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));margin-block:0}.picks .rating{margin-top:calc(var(--spacing) * 2)}td .rating-prompt,.picks .rating-prompt{display:none}td .rating button[data-label]:not(.clear),.picks .rating button[data-label]:not(.clear){padding-inline:calc(var(--spacing) * 1.5);padding-block:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}td .rating button.clear,.picks .rating button.clear{margin-left:calc(var(--spacing) * 1.5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));padding-inline:0}td .rating-note{gap:calc(var(--spacing) * 1.5);max-width:none;margin-top:0;font-size:.7rem}td .rating-note-label{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}td .rating-note input{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.rating-cell .rating{row-gap:calc(var(--spacing) * 1.5);grid-template-columns:repeat(1,minmax(0,1fr));width:15rem;display:grid}.rating-cell .rating-actions{align-items:center;width:100%;min-height:0;display:flex}.rating-cell .rating button.clear{margin-left:auto}pre.block,pre.preview,pre.journal{border-radius:var(--radius-sm);background-color:var(--paper-2);padding:calc(var(--spacing) * 3);--tw-leading:var(--leading-relaxed);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.8125rem;line-height:var(--leading-relaxed);white-space:pre-wrap;overflow-wrap:anywhere;overflow:auto}pre.block{max-height:calc(var(--spacing) * 64)}pre.preview{max-height:calc(var(--spacing) * 56)}pre.journal{max-height:34rem;padding:calc(var(--spacing) * 4)}pre.prompt,pre.learned{max-height:32rem}td>pre.preview{max-height:calc(var(--spacing) * 24);max-width:var(--container-md);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted);background-color:#0000;padding:0}details.disclosure{border-style:var(--tw-border-style);border-width:1px;border-color:var(--rule)}details.disclosure>summary{padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}details.disclosure[open]>summary{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--rule)}details.disclosure>.disclosure-body{padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}details.disclosure>.disclosure-body>*+*{margin-top:calc(var(--spacing) * 3)}details.signals>summary{min-width:0}.signals-body{margin-top:calc(var(--spacing) * 2);max-width:var(--container-2xl);border-left-style:var(--tw-border-style);border-left-width:2px;border-color:var(--rule);padding-left:calc(var(--spacing) * 3);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.signals-body>*+*{margin-top:calc(var(--spacing) * 2)}.signals-body ul{padding-left:calc(var(--spacing) * 5);list-style-type:disc}.funnel{border-radius:var(--radius-sm);background-color:var(--paper-2);width:100%;min-width:6rem}.funnel>*{border-radius:var(--radius-sm);background-color:var(--good);min-width:1px;display:block}.funnel-cell{vertical-align:middle;width:14rem;min-width:8rem}.sparklines{gap:calc(var(--spacing) * 4);grid-template-columns:repeat(auto-fit,minmax(min(18rem,100%),1fr));display:grid}.spark-figure{border-style:var(--tw-border-style);border-width:1px;border-color:var(--rule);min-width:0;padding:calc(var(--spacing) * 3);margin:0}.spark-figure figcaption{margin-bottom:calc(var(--spacing) * 2);--tw-font-weight:var(--font-weight-semibold);font-size:.7rem;font-weight:var(--font-weight-semibold);--tw-tracking:.1em;letter-spacing:.1em;color:var(--ink);text-transform:uppercase}.spark-figure figcaption .muted{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal);text-transform:none}.spark{width:100%;max-width:100%;height:auto}.spark .s0{fill:var(--good)}.spark .s1{fill:var(--loved)}.spark .s2{fill:var(--down)}.spark .s3{fill:var(--accent)}.spark .s4{fill:var(--muted)}.spark .s5{fill:var(--ink)}.spark .line{stroke:var(--accent)}.spark-axis{margin-top:var(--spacing);--tw-tracking:.08em;letter-spacing:.08em;text-transform:uppercase;justify-content:space-between;font-size:.66rem;display:flex}.spark-legend{margin-top:calc(var(--spacing) * 2);column-gap:calc(var(--spacing) * 3);row-gap:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted);flex-wrap:wrap;display:flex}.spark-legend li{align-items:center;gap:calc(var(--spacing) * 1.5);display:flex}.settings-form>*+*{margin-top:calc(var(--spacing) * 5)}.setting{gap:calc(var(--spacing) * 2);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--rule);padding-block:calc(var(--spacing) * 3);display:grid}@media (min-width:48rem){.setting{gap:calc(var(--spacing) * 6);grid-template-columns:minmax(0,19rem) minmax(0,1fr)}}.setting:first-of-type{border-top-style:var(--tw-border-style);padding-top:var(--spacing);border-top-width:0}.setting-label{min-width:0}.setting-label label{display:inline-block}.setting-label code{--tw-font-weight:var(--font-weight-medium);font-size:.85rem;font-weight:var(--font-weight-medium);color:var(--ink);overflow-wrap:anywhere;background-color:#0000;padding:0}.setting-input{min-width:0}.setting-input>input,.setting-input>select,.setting-input>textarea{width:100%;max-width:var(--container-lg)}.help,.default{margin-top:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted);overflow-wrap:anywhere}.setting-label .help{max-width:42ch}.secret{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--ink-2)}code.lines{margin-top:var(--spacing);white-space:pre-wrap;display:block}button.reset{margin-left:var(--spacing);border-style:var(--tw-border-style);min-height:0;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted);text-decoration-line:underline;-webkit-text-decoration-color:var(--rule);-webkit-text-decoration-color:var(--rule);text-decoration-color:var(--rule);text-underline-offset:2px;background-color:#0000;border-width:0;border-radius:0;padding:0;display:inline}@media (hover:hover){button.reset:hover{color:var(--ink)}}.save-bar{z-index:20;margin-inline:calc(var(--spacing) * -4);margin-top:calc(var(--spacing) * 6);justify-content:flex-end;align-items:center;column-gap:calc(var(--spacing) * 4);row-gap:calc(var(--spacing) * 2);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--rule);background-color:var(--paper);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);flex-wrap:wrap;display:flex;position:sticky;bottom:0}@media (min-width:40rem){.save-bar{margin-inline:calc(var(--spacing) * -6);padding-inline:calc(var(--spacing) * 6)}}.save-bar{box-shadow:0 -10px 18px -14px var(--ink)}@supports (color:color-mix(in lab, red, red)){.save-bar{box-shadow:0 -10px 18px -14px color-mix(in oklab, var(--ink) 55%, transparent)}}.save-bar .meta{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));margin-right:auto}.toc-progress{height:calc(var(--spacing) * .5);appearance:none;border-style:var(--tw-border-style);vertical-align:middle;background:var(--rule);border-width:0;width:100%;padding:0;display:block}.toc-progress::-webkit-progress-bar{background:var(--rule)}.toc-progress::-webkit-progress-value{background:var(--accent);transition:width .15s linear}.toc-progress::-moz-progress-bar{background:var(--accent)}.toc-progress[data-live]::-webkit-progress-value{transition:none}@media (prefers-reduced-motion:reduce){.toc-progress::-webkit-progress-value{transition:none}}[data-toc-panel]{scrollbar-width:thin;scrollbar-color:var(--rule) transparent;scrollbar-gutter:stable}[data-toc-panel]::-webkit-scrollbar{width:.5rem}[data-toc-panel]::-webkit-scrollbar-thumb{background:var(--rule);background-clip:padding-box;border:2px solid #0000}.toc-link{min-height:calc(var(--spacing) * 11);align-items:baseline;gap:calc(var(--spacing) * 2);border-left-style:var(--tw-border-style);padding-block:calc(var(--spacing) * 2.5);padding-left:calc(var(--spacing) * 3);color:var(--ink-2);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;border-color:#0000;border-left-width:2px;text-decoration-line:none;transition-duration:.15s;display:flex}@media (hover:hover){.toc-link:hover{border-color:var(--rule-strong);color:var(--accent)}}.toc-link:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--accent);--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-offset-color:var(--paper);--tw-outline-style:none;outline-style:none}@media (min-width:64rem){.toc-link{min-height:calc(var(--spacing) * 10);padding-block:calc(var(--spacing) * 1.5)}}.toc-link[data-passed],.toc-link[data-passed]>span:first-child{color:var(--ink)}.toc-link[aria-current]{border-color:var(--accent);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--ink)}.toc-toggle-icon{opacity:1;filter:blur();transition-property:opacity,scale,filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.2,0,0,1);scale:1}.toc-toggle-icon-close,[data-toc-toggle][aria-expanded=true] .toc-toggle-icon-menu{opacity:0;filter:blur(4px);scale:.25}[data-toc-toggle][aria-expanded=true] .toc-toggle-icon-close{opacity:1;filter:blur();scale:1}@media not all and (min-width:64rem){html.toc-panel-open{scrollbar-gutter:stable;overflow:hidden}.has-js [data-toc-panel][data-open=true]{height:calc(100dvh - var(--toc-panel-top,3rem));max-height:calc(100dvh - var(--toc-panel-top,3rem))}.has-js [data-toc-panel]:not([data-open=true]){display:none}}@media (max-width:40rem){.kv{display:block}.kv dt{margin-top:calc(var(--spacing) * 2)}.rating{align-items:stretch}.rating-prompt,.rating-note{flex-basis:100%}.rating-prompt{margin-bottom:var(--spacing)}.rating-actions{min-height:calc(var(--spacing) * 11)}.rating button[data-label]:after{inset-block:calc(var(--spacing) * -2)}.filters label,.filters input,.filters select{width:100%}}}@layer utilities{.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-x-0{inset-inline:0}.-inset-y-1{inset-block:calc(var(--spacing) * -1)}.-inset-y-1\.5{inset-block:calc(var(--spacing) * -1.5)}.-inset-y-2{inset-block:calc(var(--spacing) * -2)}.top-0{top:0}.top-1{top:var(--spacing)}.top-3{top:calc(var(--spacing) * 3)}.top-4{top:calc(var(--spacing) * 4)}.top-20{top:calc(var(--spacing) * 20)}.top-40{top:calc(var(--spacing) * 40)}.top-120{top:calc(var(--spacing) * 120)}.top-full{top:100%}.-bottom-px{bottom:-1px}.left-0{left:0}.left-3{left:calc(var(--spacing) * 3)}.z-20{z-index:20}.z-30{z-index:30}.z-50{z-index:50}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.m-0{margin:0}.mx-auto{margin-inline:auto}.my-4{margin-block:calc(var(--spacing) * 4)}.my-8{margin-block:calc(var(--spacing) * 8)}.my-12{margin-block:calc(var(--spacing) * 12)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-2\.5{margin-top:calc(var(--spacing) * 2.5)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-7{margin-top:calc(var(--spacing) * 7)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-10{margin-top:calc(var(--spacing) * 10)}.mt-12{margin-top:calc(var(--spacing) * 12)}.mt-14{margin-top:calc(var(--spacing) * 14)}.mt-16{margin-top:calc(var(--spacing) * 16)}.mt-auto{margin-top:auto}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.mb-9{margin-bottom:calc(var(--spacing) * 9)}.mb-10{margin-bottom:calc(var(--spacing) * 10)}.-ml-2{margin-left:calc(var(--spacing) * -2)}.-ml-px{margin-left:-1px}.ml-1{margin-left:var(--spacing)}.ml-4{margin-left:calc(var(--spacing) * 4)}.ml-auto{margin-left:auto}.line-clamp-1{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.table{display:table}.table-cell{display:table-cell}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-11{height:calc(var(--spacing) * 11)}.max-h-\[70vh\]{max-height:70vh}.max-h-\[72vh\]{max-height:72vh}.max-h-\[calc\(100vh-2rem\)\]{max-height:calc(100vh - 2rem)}.min-h-0{min-height:0}.min-h-8{min-height:calc(var(--spacing) * 8)}.min-h-10{min-height:calc(var(--spacing) * 10)}.min-h-11{min-height:calc(var(--spacing) * 11)}.min-h-12{min-height:calc(var(--spacing) * 12)}.min-h-24{min-height:calc(var(--spacing) * 24)}.min-h-\[68vh\]{min-height:68vh}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-11{width:calc(var(--spacing) * 11)}.w-14{width:calc(var(--spacing) * 14)}.w-20{width:calc(var(--spacing) * 20)}.w-60{width:calc(var(--spacing) * 60)}.w-64{width:calc(var(--spacing) * 64)}.w-\[13rem\]{width:13rem}.w-\[15rem\]{width:15rem}.w-full{width:100%}.max-w-7xl{max-width:var(--container-7xl)}.max-w-32{max-width:calc(var(--spacing) * 32)}.max-w-36{max-width:calc(var(--spacing) * 36)}.max-w-\[15rem\]{max-width:15rem}.max-w-\[58ch\]{max-width:58ch}.max-w-\[68ch\]{max-width:68ch}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:0}.min-w-10{min-width:calc(var(--spacing) * 10)}.min-w-52{min-width:calc(var(--spacing) * 52)}.min-w-\[13rem\]{min-width:13rem}.flex-1{flex:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.table-fixed{table-layout:fixed}.-translate-y-20{--tw-translate-y:calc(var(--spacing) * -20);translate:var(--tw-translate-x) var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.resize{resize:both}.scroll-mt-4{scroll-margin-top:calc(var(--spacing) * 4)}.scroll-mt-6{scroll-margin-top:calc(var(--spacing) * 6)}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-\[1fr_auto\]{grid-template-columns:1fr auto}.flex-col{flex-direction:column}.flex-nowrap{flex-wrap:nowrap}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-5{gap:calc(var(--spacing) * 5)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-2{column-gap:calc(var(--spacing) * 2)}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-x-6{column-gap:calc(var(--spacing) * 6)}.gap-y-1{row-gap:var(--spacing)}.gap-y-1\.5{row-gap:calc(var(--spacing) * 1.5)}.gap-y-3{row-gap:calc(var(--spacing) * 3)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-rule>:not(:last-child)){border-color:var(--rule)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-y-auto{overflow-y:auto}.overscroll-contain{overscroll-behavior:contain}.rounded-none{border-radius:0}.rounded-sm{border-radius:var(--radius-sm)}.rounded-l-none{border-top-left-radius:0;border-bottom-left-radius:0}.rounded-r-none{border-top-right-radius:0;border-bottom-right-radius:0}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-x-0{border-inline-style:var(--tw-border-style);border-inline-width:0}.border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.border-y-0{border-block-style:var(--tw-border-style);border-block-width:0}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-t-0{border-top-style:var(--tw-border-style);border-top-width:0}.border-t-2{border-top-style:var(--tw-border-style);border-top-width:2px}.border-t-\[3px\]{border-top-style:var(--tw-border-style);border-top-width:3px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-b-\[3px\]{border-bottom-style:var(--tw-border-style);border-bottom-width:3px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-double{--tw-border-style:double;border-style:double}.border-accent{border-color:var(--accent)}.border-ink{border-color:var(--ink)}.border-rule{border-color:var(--rule)}.border-rule-strong{border-color:var(--rule-strong)}.border-transparent{border-color:#0000}.bg-accent{background-color:var(--accent)}.bg-ink{background-color:var(--ink)}.bg-paper{background-color:var(--paper)}.bg-paper-2{background-color:var(--paper-2)}.bg-transparent{background-color:#0000}.fill-none{fill:none}.stroke-current{stroke:currentColor}.p-0{padding:0}.p-1{padding:var(--spacing)}.p-4{padding:calc(var(--spacing) * 4)}.px-0{padding-inline:0}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0{padding-block:0}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-16{padding-block:calc(var(--spacing) * 16)}.py-20{padding-block:calc(var(--spacing) * 20)}.pt-0{padding-top:0}.pt-1{padding-top:var(--spacing)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pt-5{padding-top:calc(var(--spacing) * 5)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pt-7{padding-top:calc(var(--spacing) * 7)}.pt-8{padding-top:calc(var(--spacing) * 8)}.pr-6{padding-right:calc(var(--spacing) * 6)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-7{padding-bottom:calc(var(--spacing) * 7)}.pb-9{padding-bottom:calc(var(--spacing) * 9)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-5{padding-left:calc(var(--spacing) * 5)}.pl-6{padding-left:calc(var(--spacing) * 6)}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.font-sans{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.font-serif{font-family:Newsreader,Newsreader Fallback Georgia,Newsreader Fallback Times,Newsreader Fallback Noto Serif,Newsreader Fallback DejaVu Serif,Iowan Old Style,Palatino Linotype,Georgia,serif}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[0\.8rem\]{font-size:.8rem}.text-\[0\.66rem\]{font-size:.66rem}.text-\[0\.68rem\]{font-size:.68rem}.text-\[0\.72rem\]{font-size:.72rem}.text-\[0\.95rem\]{font-size:.95rem}.text-\[1\.05rem\]{font-size:1.05rem}.leading-\[1\.1\]{--tw-leading:1.1;line-height:1.1}.leading-\[1\.2\]{--tw-leading:1.2;line-height:1.2}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[-0\.01em\]{--tw-tracking:-.01em;letter-spacing:-.01em}.tracking-\[-0\.02em\]{--tw-tracking:-.02em;letter-spacing:-.02em}.tracking-\[0\.1em\]{--tw-tracking:.1em;letter-spacing:.1em}.tracking-\[0\.08em\]{--tw-tracking:.08em;letter-spacing:.08em}.tracking-\[0\.12em\]{--tw-tracking:.12em;letter-spacing:.12em}.tracking-\[0\.15em\]{--tw-tracking:.15em;letter-spacing:.15em}.tracking-normal{--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal)}.text-wrap{text-wrap:wrap}.whitespace-nowrap{white-space:nowrap}.text-accent{color:var(--accent)}.text-down{color:var(--down)}.text-good{color:var(--good)}.text-ink{color:var(--ink)}.text-ink-2{color:var(--ink-2)}.text-loved{color:var(--loved)}.text-muted{color:var(--muted)}.text-paper{color:var(--paper)}.text-rule{color:var(--rule)}.text-warn{color:var(--warn)}.lowercase{text-transform:lowercase}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.no-underline{text-decoration-line:none}.underline{text-decoration-line:underline}.decoration-rule{-webkit-text-decoration-color:var(--rule);-webkit-text-decoration-color:var(--rule);text-decoration-color:var(--rule)}.underline-offset-4{text-underline-offset:4px}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_18px_32px_-26px_rgb\(0_0_0_\/_0\.6\)\]{--tw-shadow:0 18px 32px -26px var(--tw-shadow-color,#0009);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow\/backfill,.shadow\/compatibility,.shadow\/dry,.shadow\/maintenance{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-accent{--tw-ring-color:var(--accent)}.ring-offset-0{--tw-ring-offset-width:0px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.ring-offset-2{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.ring-offset-paper{--tw-ring-offset-color:var(--paper)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.grayscale{--tw-grayscale:grayscale(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (hover:hover){.group-hover\:text-accent:is(:where(.group):hover *){color:var(--accent)}.group-hover\:text-paper:is(:where(.group):hover *){color:var(--paper)}}.marker\:text-muted ::marker{color:var(--muted)}.marker\:text-muted::marker{color:var(--muted)}.marker\:text-muted ::-webkit-details-marker{color:var(--muted)}.marker\:text-muted::-webkit-details-marker{color:var(--muted)}@media (hover:hover){.hover\:border-accent:hover{border-color:var(--accent)}.hover\:bg-paper-2:hover{background-color:var(--paper-2)}.hover\:text-accent:hover{color:var(--accent)}.hover\:text-accent-hover:hover{color:var(--accent-hover)}.hover\:text-ink:hover{color:var(--ink)}.hover\:decoration-accent:hover{-webkit-text-decoration-color:var(--accent);-webkit-text-decoration-color:var(--accent);text-decoration-color:var(--accent)}}.focus\:translate-y-0:focus{--tw-translate-y:0px;translate:var(--tw-translate-x) var(--tw-translate-y)}.focus\:border-ink:focus{border-color:var(--ink)}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.active\:scale-\[0\.96\]:active{scale:.96}@media (min-width:40rem){.sm\:col-start-2{grid-column-start:2}.sm\:mt-12{margin-top:calc(var(--spacing) * 12)}.sm\:mt-14{margin-top:calc(var(--spacing) * 14)}.sm\:mt-16{margin-top:calc(var(--spacing) * 16)}.sm\:hidden{display:none}.sm\:inline{display:inline}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:gap-3{gap:calc(var(--spacing) * 3)}.sm\:gap-4{gap:calc(var(--spacing) * 4)}.sm\:px-6{padding-inline:calc(var(--spacing) * 6)}.sm\:py-4{padding-block:calc(var(--spacing) * 4)}.sm\:pt-6{padding-top:calc(var(--spacing) * 6)}.sm\:pr-8{padding-right:calc(var(--spacing) * 8)}.sm\:pl-6{padding-left:calc(var(--spacing) * 6)}.sm\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.sm\:text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}@media (min-width:48rem){.md\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}@media (min-width:64rem){.lg\:static{position:static}.lg\:sticky{position:sticky}.lg\:inset-x-auto{inset-inline:auto}.lg\:top-0{top:0}.lg\:top-6{top:calc(var(--spacing) * 6)}.lg\:z-10{z-index:10}.lg\:z-auto{z-index:auto}.lg\:mt-4{margin-top:calc(var(--spacing) * 4)}.lg\:mt-12{margin-top:calc(var(--spacing) * 12)}.lg\:block{display:block}.lg\:grid{display:grid}.lg\:hidden{display:none}.lg\:max-h-\[calc\(100dvh-3rem\)\]{max-height:calc(100dvh - 3rem)}.lg\:max-h-\[calc\(100vh-3rem\)\]{max-height:calc(100vh - 3rem)}.lg\:w-84{width:calc(var(--spacing) * 84)}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-\[16rem_minmax\(0\,1fr\)\]{grid-template-columns:16rem minmax(0,1fr)}.lg\:gap-x-10{column-gap:calc(var(--spacing) * 10)}.lg\:overflow-y-auto{overflow-y:auto}.lg\:border-0{border-style:var(--tw-border-style);border-width:0}.lg\:bg-paper{background-color:var(--paper)}.lg\:px-0{padding-inline:0}.lg\:px-6{padding-inline:calc(var(--spacing) * 6)}.lg\:pt-0{padding-top:0}.lg\:pr-3{padding-right:calc(var(--spacing) * 3)}.lg\:pb-3{padding-bottom:calc(var(--spacing) * 3)}.lg\:pb-10{padding-bottom:calc(var(--spacing) * 10)}.lg\:pl-0{padding-left:0}.lg\:shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}@media (min-width:80rem){.xl\:w-72{width:calc(var(--spacing) * 72)}.xl\:grid-cols-\[18rem_minmax\(0\,1fr\)\]{grid-template-columns:18rem minmax(0,1fr)}.xl\:gap-x-14{column-gap:calc(var(--spacing) * 14)}}.\[\&_\.comment-meta\]\:font-sans .comment-meta{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.\[\&_\.comment-meta\]\:text-sm .comment-meta{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.\[\&_\.comment-meta\]\:text-muted .comment-meta{color:var(--muted)}.\[\&_blockquote\.reply\]\:ml-6 blockquote.reply{margin-left:calc(var(--spacing) * 6)}.\[\&\:\:-webkit-details-marker\]\:hidden::-webkit-details-marker{display:none}.\[\&\>p\:first-child\]\:first-letter\:float-left>p:first-child:first-letter{float:left}.\[\&\>p\:first-child\]\:first-letter\:mt-1>p:first-child:first-letter{margin-top:var(--spacing)}.\[\&\>p\:first-child\]\:first-letter\:mr-2>p:first-child:first-letter{margin-right:calc(var(--spacing) * 2)}.\[\&\>p\:first-child\]\:first-letter\:font-serif>p:first-child:first-letter{font-family:Newsreader,Newsreader Fallback Georgia,Newsreader Fallback Times,Newsreader Fallback Noto Serif,Newsreader Fallback DejaVu Serif,Iowan Old Style,Palatino Linotype,Georgia,serif}.\[\&\>p\:first-child\]\:first-letter\:text-\[4\.6rem\]>p:first-child:first-letter{font-size:4.6rem}.\[\&\>p\:first-child\]\:first-letter\:leading-\[0\.72\]>p:first-child:first-letter{--tw-leading:.72;line-height:.72}.\[\&\>p\:first-child\]\:first-letter\:font-semibold>p:first-child:first-letter{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}}@font-face{font-family:Newsreader;font-style:normal;font-weight:200 800;font-stretch:100%;font-display:swap;src:url(/static/Newsreader.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Newsreader;font-style:italic;font-weight:200 800;font-stretch:100%;font-display:swap;src:url(/static/Newsreader-italic.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Newsreader Fallback Georgia;src:local(Georgia);size-adjust:93.88%;ascent-override:78.29%;descent-override:28.23%;line-gap-override:0%}@font-face{font-family:Newsreader Fallback Times;src:local(Times New Roman),local(Liberation Serif),local(Tinos);size-adjust:103.02%;ascent-override:71.35%;descent-override:25.72%;line-gap-override:0%}@font-face{font-family:Newsreader Fallback Noto Serif;src:local(Noto Serif);size-adjust:87.01%;ascent-override:84.48%;descent-override:30.46%;line-gap-override:0%}@font-face{font-family:Newsreader Fallback DejaVu Serif;src:local(DejaVu Serif);size-adjust:81.01%;ascent-override:90.73%;descent-override:32.71%;line-gap-override:0%}:root{--paper:#f6f3ec;--paper-2:#ece7db;--ink:#1c1b18;--ink-2:#4f4b43;--muted:#6b665a;--rule:#d8d2c4;--rule-strong:#1c1b18;--accent:#a3231f;--accent-hover:#7c1a16;--loved:#2f6f46;--good:#2f6a8f;--down:#9c3f36;--warn:#7d631c;color-scheme:light}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--paper:#151513;--paper-2:#1e1d1a;--ink:#ebe6da;--ink-2:#bfb9aa;--muted:#8f8a7d;--rule:#3a3833;--rule-strong:#ebe6da;--accent:#ef8c82;--accent-hover:#f7aaa2;--loved:#7fcb92;--good:#7fb8d8;--down:#ea8f84;--warn:#d9b45a;color-scheme:dark}}:root[data-theme=dark]{--paper:#151513;--paper-2:#1e1d1a;--ink:#ebe6da;--ink-2:#bfb9aa;--muted:#8f8a7d;--rule:#3a3833;--rule-strong:#ebe6da;--accent:#ef8c82;--accent-hover:#f7aaa2;--loved:#7fcb92;--good:#7fb8d8;--down:#ea8f84;--warn:#d9b45a;color-scheme:dark}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false} \ No newline at end of file +@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--font-serif:"Newsreader", "Newsreader Fallback Georgia", "Newsreader Fallback Times", "Newsreader Fallback Noto Serif", "Newsreader Fallback DejaVu Serif", "Iowan Old Style", "Palatino Linotype", Georgia, serif;--font-mono:ui-monospace, SFMono-Regular, Menlo, monospace;--spacing:.25rem;--container-md:28rem;--container-lg:32rem;--container-2xl:42rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--tracking-normal:0em;--leading-tight:1.25;--leading-snug:1.375;--leading-normal:1.5;--leading-relaxed:1.625;--radius-sm:.25rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--default-mono-font-family:ui-monospace, SFMono-Regular, Menlo, monospace;--color-paper:var(--paper);--color-paper-2:var(--paper-2);--color-ink:var(--ink)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])),[hidden]{display:none!important}html{background-color:var(--paper);color:var(--ink);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{background-color:var(--paper);--tw-leading:1.65;min-height:100vh;color:var(--ink);font-optical-sizing:auto;margin:0;font-family:Newsreader,Newsreader Fallback Georgia,Newsreader Fallback Times,Newsreader Fallback Noto Serif,Newsreader Fallback DejaVu Serif,Iowan Old Style,Palatino Linotype,Georgia,serif;font-size:1.0625rem;line-height:1.65}::selection{background:var(--accent)}@supports (color:color-mix(in lab, red, red)){::selection{background:color-mix(in oklab, var(--accent) 24%, transparent)}}a{color:var(--accent);-webkit-text-decoration-color:var(--rule);-webkit-text-decoration-color:var(--rule);text-decoration-color:var(--rule);text-underline-offset:4px;transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}@media (hover:hover){a:hover{color:var(--accent-hover)}}a:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--accent);--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-offset-color:var(--paper);--tw-outline-style:none;outline-style:none}h1,h2,h3{color:var(--ink);font-optical-sizing:auto}button,input,select,textarea{font:inherit;border-radius:var(--radius-sm);border-style:var(--tw-border-style);border-width:1px;border-color:var(--rule);background-color:var(--paper);padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * 1.5);color:var(--ink);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}:is(button,input,select,textarea)::placeholder{color:var(--muted)}:is(button,input,select,textarea):focus{border-color:var(--ink);--tw-outline-style:none;outline-style:none}:is(button,input,select,textarea):focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--accent);--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-offset-color:var(--paper)}button{cursor:pointer}button:disabled,input:disabled,select:disabled,textarea:disabled{cursor:not-allowed;border-color:var(--rule);background-color:var(--paper-2);color:var(--muted)}textarea{min-height:calc(var(--spacing) * 28)}summary{cursor:pointer}table{border-collapse:collapse;width:100%;font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-snug);line-height:var(--leading-snug);font-variant-numeric:tabular-nums}thead{z-index:10;background-color:var(--paper);position:sticky;top:0}th,td{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--rule);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 2);text-align:left;vertical-align:top}th{--tw-font-weight:var(--font-weight-semibold);font-size:.72rem;font-weight:var(--font-weight-semibold);--tw-tracking:.1em;letter-spacing:.1em;color:var(--muted);text-transform:uppercase}tbody tr{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;transition-duration:.15s}@media (hover:hover){tbody tr:hover{background-color:var(--paper-2)}}code,pre{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}meter{height:calc(var(--spacing) * 2);border-radius:var(--radius-sm);appearance:none;background:var(--rule);width:100%;display:block}meter::-webkit-meter-bar{background:var(--rule);border:0;border-radius:2px;height:.5rem}meter::-webkit-meter-optimum-value{background:var(--good);border-radius:2px}meter::-webkit-meter-suboptimum-value{background:var(--good);border-radius:2px}meter::-webkit-meter-even-less-good-value{background:var(--good);border-radius:2px}meter.over::-webkit-meter-optimum-value{background:var(--down)}meter.over::-webkit-meter-suboptimum-value{background:var(--down)}meter.over::-webkit-meter-even-less-good-value{background:var(--down)}meter::-moz-meter-bar{background:var(--good);border-radius:2px}meter.over::-moz-meter-bar{background:var(--down)}@media (prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition-duration:.01ms!important}}}@layer components{.btn,.button{min-height:calc(var(--spacing) * 10);border-radius:var(--radius-sm);border-style:var(--tw-border-style);border-width:1px;border-color:var(--rule-strong);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--ink);--tw-duration:.15s;background-color:#0000;justify-content:center;align-items:center;text-decoration-line:none;transition-duration:.15s;display:inline-flex}@media (hover:hover){:is(.btn,.button):hover{background-color:var(--ink);color:var(--paper)}}:is(.btn,.button):focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--accent);--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-offset-color:var(--paper);--tw-outline-style:none;outline-style:none}.btn,.button{transition-property:transform,background-color,color,border-color}.btn-primary{min-height:calc(var(--spacing) * 10);border-radius:var(--radius-sm);border-style:var(--tw-border-style);border-width:1px;border-color:var(--ink);background-color:var(--ink);padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 1.5);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--paper);--tw-duration:.15s;justify-content:center;align-items:center;text-decoration-line:none;transition-duration:.15s;display:inline-flex}@media (hover:hover){.btn-primary:hover{border-color:var(--accent);background-color:var(--accent);color:var(--paper)}}.btn-primary:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--accent);--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-offset-color:var(--paper);--tw-outline-style:none;outline-style:none}.btn-primary{transition-property:transform,background-color,color,border-color}.btn-quiet{min-height:calc(var(--spacing) * 9);align-items:center;gap:var(--spacing);border-radius:var(--radius-sm);border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 2);padding-block:var(--spacing);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted);text-decoration-line:underline;-webkit-text-decoration-color:var(--rule);-webkit-text-decoration-color:var(--rule);text-decoration-color:var(--rule);text-underline-offset:4px;background-color:#0000;border-width:0;display:inline-flex}@media (hover:hover){.btn-quiet:hover{color:var(--ink);-webkit-text-decoration-color:var(--accent);-webkit-text-decoration-color:var(--accent);text-decoration-color:var(--accent)}}.btn:disabled,.btn-primary:disabled,.btn-danger:disabled{cursor:not-allowed;border-color:var(--rule);background-color:var(--paper-2);color:var(--muted)}@media (hover:hover){:is(.btn:disabled,.btn-primary:disabled,.btn-danger:disabled):hover{background-color:var(--paper-2);color:var(--muted)}}.btn-danger,button.danger{min-height:calc(var(--spacing) * 9);border-radius:var(--radius-sm);border-style:var(--tw-border-style);border-width:1px;border-color:var(--down);padding-inline:calc(var(--spacing) * 2.5);padding-block:var(--spacing);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--down);--tw-duration:.15s;background-color:#0000;justify-content:center;align-items:center;transition-duration:.15s;display:inline-flex}@media (hover:hover){:is(.btn-danger,button.danger):hover{background-color:var(--down);color:var(--paper)}}.btn-danger,button.danger{transition-property:transform,background-color,color,border-color}.btn:active,.button:active,.btn-primary:active,.btn-danger:active,button.danger:active{transform:scale(.96)}.badge{padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * .5);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);white-space:nowrap;--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);color:var(--ink-2);background:var(--ink);border-radius:3.40282e38px;align-items:center;display:inline-flex}@supports (color:color-mix(in lab, red, red)){.badge{background:color-mix(in oklab, var(--ink) 8%, transparent)}}.badge.selected,.badge.loved,.badge.ok{color:var(--loved);background:var(--loved)}@supports (color:color-mix(in lab, red, red)){.badge.selected,.badge.loved,.badge.ok{background:color-mix(in oklab, var(--loved) 14%, transparent)}}.badge.good,.badge.assessed,.badge.triaged,.badge.degraded{color:var(--good);background:var(--good)}@supports (color:color-mix(in lab, red, red)){.badge.good,.badge.assessed,.badge.triaged,.badge.degraded{background:color-mix(in oklab, var(--good) 14%, transparent)}}.badge.down,.badge.slop,.badge.excluded,.badge.failed,.badge.dry_run{color:var(--down);background:var(--down)}@supports (color:color-mix(in lab, red, red)){.badge.down,.badge.slop,.badge.excluded,.badge.failed,.badge.dry_run{background:color-mix(in oklab, var(--down) 14%, transparent)}}.badge.shortlisted,.badge.admitted,.badge.eligible,.badge.cleared,.badge.reason,.badge.running,.badge.requested{color:var(--muted);background:var(--muted)}@supports (color:color-mix(in lab, red, red)){.badge.shortlisted,.badge.admitted,.badge.eligible,.badge.cleared,.badge.reason,.badge.running,.badge.requested{background:color-mix(in oklab, var(--muted) 14%, transparent)}}.badge.restart,.badge.warn{color:var(--warn);background:var(--warn)}@supports (color:color-mix(in lab, red, red)){.badge.restart,.badge.warn{background:color-mix(in oklab, var(--warn) 16%, transparent)}}.kv{column-gap:calc(var(--spacing) * 5);row-gap:calc(var(--spacing) * 1.5);grid-template-columns:minmax(9rem,1fr) 2fr;display:grid}.kv dt{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted)}.kv dd{min-width:0;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));overflow-wrap:anywhere;margin:0}.scroll-x{overscroll-behavior-inline:contain;max-width:100%;overflow-x:auto}.scroll-x>table{min-width:max-content}.scroll-x.tall{overscroll-behavior-block:contain;max-height:70vh;overflow-y:auto}.reader-page{overflow-wrap:anywhere;min-width:0}.prose-body{--tw-leading:1.72;color:var(--ink);font-size:1.0625rem;line-height:1.72}.prose-body>*+*{margin-top:calc(var(--spacing) * 5)}.prose-body p,.index-summary{text-wrap:pretty}.prose-body h2{margin-top:calc(var(--spacing) * 10);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--rule);padding-top:calc(var(--spacing) * 4);font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height));--tw-leading:1.1;--tw-font-weight:var(--font-weight-semibold);line-height:1.1;font-weight:var(--font-weight-semibold);--tw-tracking:-.01em;letter-spacing:-.01em}.prose-body h3{margin-top:calc(var(--spacing) * 8);font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height));--tw-leading:1.15;--tw-font-weight:var(--font-weight-semibold);line-height:1.15;font-weight:var(--font-weight-semibold);--tw-tracking:-.01em;letter-spacing:-.01em}.prose-body a{color:var(--ink);text-decoration-line:underline;-webkit-text-decoration-color:var(--rule);-webkit-text-decoration-color:var(--rule);text-decoration-color:var(--rule);text-underline-offset:4px}@media (hover:hover){.prose-body a:hover{color:var(--ink);-webkit-text-decoration-color:var(--accent);-webkit-text-decoration-color:var(--accent);text-decoration-color:var(--accent)}}.prose-body img{margin-inline:auto;margin-block:calc(var(--spacing) * 7);border-radius:var(--radius-sm);text-align:center;max-width:100%;height:auto;font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted);outline-offset:-1px;outline:1px solid oklch(0% 0 0/.1);font-style:italic;display:block}@media (prefers-color-scheme:dark){:root:not([data-theme=light]) .prose-body img{outline-color:oklch(100% 0 0/.1)}}:root[data-theme=dark] .prose-body img{outline-color:oklch(100% 0 0/.1)}.prose-body table{overscroll-behavior-inline:contain;max-width:100%;display:block;overflow-x:auto}.prose-body th,.prose-body td{overflow-wrap:normal}.prose-body pre{border-radius:var(--radius-sm);background-color:var(--paper-2);max-width:100%;padding:calc(var(--spacing) * 4);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);overflow-x:auto}.prose-body :not(pre)>code{border-radius:var(--radius-sm);background-color:var(--paper-2);padding-inline:var(--spacing);padding-block:calc(var(--spacing) * .5);font-size:.9em}.prose-body blockquote{margin-block:calc(var(--spacing) * 7);border-left-style:var(--tw-border-style);border-left-width:2px;border-color:var(--rule-strong);padding-left:calc(var(--spacing) * 5);color:var(--ink-2)}.prose-body ul{padding-left:calc(var(--spacing) * 6);list-style-type:disc}.prose-body ol{padding-left:calc(var(--spacing) * 6);list-style-type:decimal}.prose-body li::marker{color:var(--muted)}.prose-body li+li{margin-top:calc(var(--spacing) * 2)}.reader-page :where(h1,h2,h3,h4),.reader-section-heading{text-wrap:balance}.reader-section-heading{border-top-style:var(--tw-border-style);--tw-border-style:double;border-style:double;border-top-width:3px;border-color:var(--rule-strong);padding-top:calc(var(--spacing) * 3);--tw-leading:1.2;--tw-font-weight:var(--font-weight-semibold);font-family:Newsreader,Newsreader Fallback Georgia,Newsreader Fallback Times,Newsreader Fallback Noto Serif,Newsreader Fallback DejaVu Serif,Iowan Old Style,Palatino Linotype,Georgia,serif;font-size:1.05rem;line-height:1.2;font-weight:var(--font-weight-semibold);--tw-tracking:.15em;letter-spacing:.15em;color:var(--ink);text-transform:uppercase}.rating{margin-block:calc(var(--spacing) * 5);align-items:center;column-gap:calc(var(--spacing) * 3);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));flex-wrap:wrap;display:flex}.rating-prompt{color:var(--muted);font-family:Newsreader,Newsreader Fallback Georgia,Newsreader Fallback Times,Newsreader Fallback Noto Serif,Newsreader Fallback DejaVu Serif,Iowan Old Style,Palatino Linotype,Georgia,serif;font-size:.8rem;font-style:italic}.rating-actions{min-height:calc(var(--spacing) * 10);white-space:nowrap;align-items:center;display:flex}.rating button[data-label]{height:calc(var(--spacing) * 8);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-duration:.15s;transition-property:transform,background-color,color,border-color;transition-duration:.15s;position:relative}.rating button[data-label]:after{content:"";inset-inline:0;inset-block:calc(var(--spacing) * -1.5);position:absolute}.rating button[data-label]:active{transform:scale(.96)}.rating button[data-label]:focus-visible{z-index:20;--tw-ring-offset-width:0px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.rating button[data-label]:not(.clear){border-color:var(--rule);padding-inline:calc(var(--spacing) * 2);padding-block:var(--spacing);color:var(--ink-2);background-color:#0000;border-radius:0;margin-left:-1px}.rating button[data-label]:not(.clear):first-child{border-top-left-radius:var(--radius-sm);border-bottom-left-radius:var(--radius-sm);margin-left:0}.rating button[data-label]:not(.clear):last-child{border-top-right-radius:var(--radius-sm);border-bottom-right-radius:var(--radius-sm)}@media (hover:hover){.rating button[data-label]:not(.clear):hover{z-index:10;border-color:var(--ink);background-color:var(--paper-2);color:var(--ink)}}.rating button.active[data-label=loved]{z-index:10;border-color:var(--loved);color:var(--loved);background:var(--loved)}@supports (color:color-mix(in lab, red, red)){.rating button.active[data-label=loved]{background:color-mix(in oklab, var(--loved) 14%, transparent)}}.rating button.active[data-label=good]{z-index:10;border-color:var(--good);color:var(--good);background:var(--good)}@supports (color:color-mix(in lab, red, red)){.rating button.active[data-label=good]{background:color-mix(in oklab, var(--good) 14%, transparent)}}.rating button.active[data-label=down],.rating button.active[data-label=slop]{z-index:10;border-color:var(--down);color:var(--down);background:var(--down)}@supports (color:color-mix(in lab, red, red)){.rating button.active[data-label=down],.rating button.active[data-label=slop]{background:color-mix(in oklab, var(--down) 14%, transparent)}}.rating button.clear{visibility:hidden;margin-left:calc(var(--spacing) * 1.5);border-style:var(--tw-border-style);padding-inline:var(--spacing);color:var(--muted);text-decoration-line:underline;-webkit-text-decoration-color:var(--rule);-webkit-text-decoration-color:var(--rule);text-decoration-color:var(--rule);text-underline-offset:4px;background-color:#0000;border-width:0}@media (hover:hover){.rating button.clear:hover{color:var(--ink)}}.rating:has(button[data-label]:not(.clear).active) button.clear,.rating button.clear.active{visibility:visible}.rating button.clear.active{text-decoration-line:none}.rating-cleared-label,.rating button.clear.active .rating-clear-label{display:none}.rating button.clear.active .rating-cleared-label{display:inline}.rating-note{margin-top:calc(var(--spacing) * 2);width:100%;max-width:var(--container-md);align-items:center;gap:calc(var(--spacing) * 2);color:var(--muted);flex-basis:100%;font-size:.72rem;display:flex}.rating-note input{border-inline-style:var(--tw-border-style);border-inline-width:0;border-top-style:var(--tw-border-style);border-top-width:0;border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--rule);min-width:0;padding-inline:0;padding-block:var(--spacing);--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);background-color:#0000;border-radius:0;flex:1}.rating-note input:focus{border-color:var(--ink)}.flash{margin-block:calc(var(--spacing) * 4);border-left-style:var(--tw-border-style);border-left-width:4px;border-color:var(--accent);background-color:var(--paper-2);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.error{border-left-style:var(--tw-border-style);border-left-width:4px;border-color:var(--down);background-color:var(--paper-2);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--down)}.notice{border-left-style:var(--tw-border-style);border-left-width:4px;border-color:var(--warn);background-color:var(--paper-2);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--ink-2)}ul.error,ul.notice{padding-left:calc(var(--spacing) * 8);list-style-type:disc}.dashboard{margin-inline:auto;margin-block:calc(var(--spacing) * 8);max-width:var(--container-7xl);padding-inline:calc(var(--spacing) * 4);padding-bottom:calc(var(--spacing) * 6);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-leading:var(--leading-normal);line-height:var(--leading-normal)}@media (min-width:40rem){.dashboard{padding-inline:calc(var(--spacing) * 6)}}.dashboard>*+*{margin-top:calc(var(--spacing) * 4)}.dashboard h1{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height));--tw-leading:var(--leading-tight);line-height:var(--leading-tight);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:-.01em;letter-spacing:-.01em}.dashboard h2{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.dashboard h3{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.dashboard>h2{margin-top:calc(var(--spacing) * 9);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--rule);padding-top:calc(var(--spacing) * 3);--tw-font-weight:var(--font-weight-semibold);font-size:.78rem;font-weight:var(--font-weight-semibold);--tw-tracking:.14em;letter-spacing:.14em;color:var(--muted);text-transform:uppercase}.dashboard>p,.dashboard>ul,.dashboard>ol{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.dashboard code{border-radius:var(--radius-sm);background-color:var(--paper-2);padding-inline:var(--spacing);padding-block:calc(var(--spacing) * .5);font-size:.85em}.dashboard pre code{background-color:#0000;padding:0}.dashboard table a{color:var(--ink);text-decoration-line:underline;-webkit-text-decoration-color:var(--rule);-webkit-text-decoration-color:var(--rule);text-decoration-color:var(--rule);text-underline-offset:2px}@media (hover:hover){.dashboard table a:hover{color:var(--ink);-webkit-text-decoration-color:var(--accent);-webkit-text-decoration-color:var(--accent);text-decoration-color:var(--accent)}}.page-head{justify-content:space-between;align-items:flex-end;column-gap:calc(var(--spacing) * 6);row-gap:calc(var(--spacing) * 3);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--rule);padding-bottom:calc(var(--spacing) * 4);flex-wrap:wrap;display:flex}.page-head>div:first-child{min-width:0}.dashboard>.page-head+*{margin-top:calc(var(--spacing) * 6)}.page-desc{margin-top:calc(var(--spacing) * 1.5);max-width:74ch;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted)}.page-desc a{color:var(--accent)}.page-actions{align-items:center;gap:calc(var(--spacing) * 2);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));flex-wrap:wrap;display:flex}.page-eyebrow{--tw-tracking:.14em;letter-spacing:.14em;color:var(--muted);text-transform:uppercase;font-size:.7rem}.tiles{gap:calc(var(--spacing) * 3);grid-template-columns:repeat(auto-fit,minmax(min(10.5rem,100%),1fr));display:grid}.tile{border-style:var(--tw-border-style);border-width:1px;border-color:var(--rule);min-width:0;padding-inline:calc(var(--spacing) * 3.5);padding-block:calc(var(--spacing) * 3)}.tile-label{--tw-font-weight:var(--font-weight-medium);font-size:.68rem;font-weight:var(--font-weight-medium);--tw-tracking:.12em;letter-spacing:.12em;color:var(--muted);text-transform:uppercase;display:block}.tile-num{margin-top:var(--spacing);--tw-leading:var(--leading-tight);font-size:1.55rem;line-height:var(--leading-tight);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:-.01em;letter-spacing:-.01em;font-variant-numeric:tabular-nums;overflow-wrap:anywhere;display:block}.tile-delta{margin-top:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted);overflow-wrap:anywhere;display:block}.cards{gap:calc(var(--spacing) * 4);grid-template-columns:repeat(auto-fit,minmax(min(20rem,100%),1fr));display:grid}.card{border-style:var(--tw-border-style);border-width:1px;border-color:var(--rule);min-width:0;padding:calc(var(--spacing) * 4)}.card>*+*{margin-top:calc(var(--spacing) * 3)}.card h2,.card h3{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.card>h2:first-child,.card>h3:first-child{margin-top:0}.card p,.card li{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.muted,.meta{color:var(--muted)}.jobs a,.picks>li>a:first-child{color:var(--ink);text-decoration-line:none}@media (hover:hover){:is(.jobs a,.picks>li>a:first-child):hover{color:var(--accent)}}.num{text-align:right;white-space:nowrap;--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.cell-wrap{white-space:normal;overflow-wrap:anywhere;min-width:10rem;max-width:24rem}.cell-tight{white-space:nowrap}.filters{align-items:flex-end;column-gap:calc(var(--spacing) * 4);row-gap:calc(var(--spacing) * 3);border-block-style:var(--tw-border-style);border-block-width:1px;border-color:var(--rule);padding-block:calc(var(--spacing) * 3);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));flex-wrap:wrap;display:flex}.filters label{gap:var(--spacing);--tw-font-weight:var(--font-weight-medium);font-size:.66rem;font-weight:var(--font-weight-medium);--tw-tracking:.1em;letter-spacing:.1em;color:var(--muted);text-transform:uppercase;display:grid}.filters input,.filters select,.filters textarea{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal);color:var(--ink);text-transform:none}.filters select,.filters input[type=date]{min-width:calc(var(--spacing) * 32)}.filters .filter-actions{align-items:center;gap:calc(var(--spacing) * 3);display:flex}.form-inline{align-items:center;gap:calc(var(--spacing) * 3);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));flex-wrap:wrap;display:flex}.form-inline label{align-items:center;gap:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:flex}.table-filter{margin-block:calc(var(--spacing) * 2);width:calc(var(--spacing) * 80);max-width:100%;font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));display:none}.has-js .table-filter{display:block}[data-theme-icon],[data-theme-label]{display:none}html:not([data-theme]) [data-theme-icon=system],html[data-theme=light] [data-theme-icon=light],html[data-theme=dark] [data-theme-icon=dark]{display:block}html:not([data-theme]) [data-theme-label=system],html[data-theme=light] [data-theme-label=light],html[data-theme=dark] [data-theme-label=dark]{display:inline}.pager{justify-content:space-between;align-items:center;column-gap:calc(var(--spacing) * 6);row-gap:calc(var(--spacing) * 2);padding-block:var(--spacing);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted);--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);flex-wrap:wrap;display:flex}.pager a{color:var(--ink);text-decoration-line:none}@media (hover:hover){.pager a:hover{color:var(--accent)}}.run-nav{justify-content:space-between;align-items:center;column-gap:calc(var(--spacing) * 6);row-gap:calc(var(--spacing) * 2);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));flex-wrap:wrap;display:flex}.run-nav a{color:var(--ink);text-decoration-line:none}@media (hover:hover){.run-nav a:hover{color:var(--accent)}}.tabs{align-items:center;column-gap:calc(var(--spacing) * 6);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--rule);--tw-font-weight:var(--font-weight-medium);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:.72rem;font-weight:var(--font-weight-medium);--tw-tracking:.12em;letter-spacing:.12em;text-transform:uppercase;flex-wrap:wrap;display:flex}.tabs a{min-height:calc(var(--spacing) * 10);border-bottom-style:var(--tw-border-style);color:var(--muted);border-color:#0000;border-bottom-width:2px;align-items:center;margin-bottom:-1px;text-decoration-line:none;display:flex}@media (hover:hover){.tabs a:hover{color:var(--ink)}}.tabs a.active{border-color:var(--accent);color:var(--ink)}.pagination{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted);--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}tr.superseded>td,tr.superseded a{color:var(--muted)}td .rating,.picks .rating{row-gap:var(--spacing);max-width:none;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));margin-block:0}.picks .rating{margin-top:calc(var(--spacing) * 2)}td .rating-prompt,.picks .rating-prompt{display:none}td .rating button[data-label]:not(.clear),.picks .rating button[data-label]:not(.clear){padding-inline:calc(var(--spacing) * 1.5);padding-block:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}td .rating button.clear,.picks .rating button.clear{margin-left:calc(var(--spacing) * 1.5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));padding-inline:0}td .rating-note{gap:calc(var(--spacing) * 1.5);max-width:none;margin-top:0;font-size:.7rem}td .rating-note-label{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}td .rating-note input{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.rating-cell .rating{row-gap:calc(var(--spacing) * 1.5);grid-template-columns:repeat(1,minmax(0,1fr));width:18rem;display:grid}.rating-cell .rating-actions{align-items:center;width:100%;min-height:0;display:flex}.rating-cell .rating button.clear{margin-left:auto}pre.block,pre.preview,pre.journal{border-radius:var(--radius-sm);background-color:var(--paper-2);padding:calc(var(--spacing) * 3);--tw-leading:var(--leading-relaxed);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.8125rem;line-height:var(--leading-relaxed);white-space:pre-wrap;overflow-wrap:anywhere;overflow:auto}pre.block{max-height:calc(var(--spacing) * 64)}pre.preview{max-height:calc(var(--spacing) * 56)}pre.journal{max-height:34rem;padding:calc(var(--spacing) * 4)}pre.prompt,pre.learned{max-height:32rem}td>pre.preview{max-height:calc(var(--spacing) * 24);max-width:var(--container-md);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted);background-color:#0000;padding:0}details.disclosure{border-style:var(--tw-border-style);border-width:1px;border-color:var(--rule)}details.disclosure>summary{padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}details.disclosure[open]>summary{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--rule)}details.disclosure>.disclosure-body{padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}details.disclosure>.disclosure-body>*+*{margin-top:calc(var(--spacing) * 3)}details.signals>summary{min-width:0}.signals-body{margin-top:calc(var(--spacing) * 2);max-width:var(--container-2xl);border-left-style:var(--tw-border-style);border-left-width:2px;border-color:var(--rule);padding-left:calc(var(--spacing) * 3);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.signals-body>*+*{margin-top:calc(var(--spacing) * 2)}.signals-body ul{padding-left:calc(var(--spacing) * 5);list-style-type:disc}.funnel{border-radius:var(--radius-sm);background-color:var(--paper-2);width:100%;min-width:6rem}.funnel>*{border-radius:var(--radius-sm);background-color:var(--good);min-width:1px;display:block}.funnel-cell{vertical-align:middle;width:14rem;min-width:8rem}.sparklines{gap:calc(var(--spacing) * 4);grid-template-columns:repeat(auto-fit,minmax(min(18rem,100%),1fr));display:grid}.spark-figure{border-style:var(--tw-border-style);border-width:1px;border-color:var(--rule);min-width:0;padding:calc(var(--spacing) * 3);margin:0}.spark-figure figcaption{margin-bottom:calc(var(--spacing) * 2);--tw-font-weight:var(--font-weight-semibold);font-size:.7rem;font-weight:var(--font-weight-semibold);--tw-tracking:.1em;letter-spacing:.1em;color:var(--ink);text-transform:uppercase}.spark-figure figcaption .muted{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal);text-transform:none}.spark{width:100%;max-width:100%;height:auto}.spark .s0{fill:var(--good)}.spark .s1{fill:var(--loved)}.spark .s2{fill:var(--down)}.spark .s3{fill:var(--accent)}.spark .s4{fill:var(--muted)}.spark .s5{fill:var(--ink)}.spark .line{stroke:var(--accent)}.spark-axis{margin-top:var(--spacing);--tw-tracking:.08em;letter-spacing:.08em;text-transform:uppercase;justify-content:space-between;font-size:.66rem;display:flex}.spark-legend{margin-top:calc(var(--spacing) * 2);column-gap:calc(var(--spacing) * 3);row-gap:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted);flex-wrap:wrap;display:flex}.spark-legend li{align-items:center;gap:calc(var(--spacing) * 1.5);display:flex}.settings-form>*+*{margin-top:calc(var(--spacing) * 5)}.setting{gap:calc(var(--spacing) * 2);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--rule);padding-block:calc(var(--spacing) * 3);display:grid}@media (min-width:48rem){.setting{gap:calc(var(--spacing) * 6);grid-template-columns:minmax(0,19rem) minmax(0,1fr)}}.setting:first-of-type{border-top-style:var(--tw-border-style);padding-top:var(--spacing);border-top-width:0}.setting-label{min-width:0}.setting-label label{display:inline-block}.setting-label code{--tw-font-weight:var(--font-weight-medium);font-size:.85rem;font-weight:var(--font-weight-medium);color:var(--ink);overflow-wrap:anywhere;background-color:#0000;padding:0}.setting-input{min-width:0}.setting-input>input,.setting-input>select,.setting-input>textarea{width:100%;max-width:var(--container-lg)}.help,.default{margin-top:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted);overflow-wrap:anywhere}.setting-label .help{max-width:42ch}.secret{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--ink-2)}code.lines{margin-top:var(--spacing);white-space:pre-wrap;display:block}button.reset{margin-left:var(--spacing);border-style:var(--tw-border-style);min-height:0;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted);text-decoration-line:underline;-webkit-text-decoration-color:var(--rule);-webkit-text-decoration-color:var(--rule);text-decoration-color:var(--rule);text-underline-offset:2px;background-color:#0000;border-width:0;border-radius:0;padding:0;display:inline}@media (hover:hover){button.reset:hover{color:var(--ink)}}.save-bar{z-index:20;margin-inline:calc(var(--spacing) * -4);margin-top:calc(var(--spacing) * 6);justify-content:flex-end;align-items:center;column-gap:calc(var(--spacing) * 4);row-gap:calc(var(--spacing) * 2);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--rule);background-color:var(--paper);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 3);flex-wrap:wrap;display:flex;position:sticky;bottom:0}@media (min-width:40rem){.save-bar{margin-inline:calc(var(--spacing) * -6);padding-inline:calc(var(--spacing) * 6)}}.save-bar{box-shadow:0 -10px 18px -14px var(--ink)}@supports (color:color-mix(in lab, red, red)){.save-bar{box-shadow:0 -10px 18px -14px color-mix(in oklab, var(--ink) 55%, transparent)}}.save-bar .meta{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));margin-right:auto}.toc-progress{height:calc(var(--spacing) * .5);appearance:none;border-style:var(--tw-border-style);vertical-align:middle;background:var(--rule);border-width:0;width:100%;padding:0;display:block}.toc-progress::-webkit-progress-bar{background:var(--rule)}.toc-progress::-webkit-progress-value{background:var(--accent);transition:width .15s linear}.toc-progress::-moz-progress-bar{background:var(--accent)}.toc-progress[data-live]::-webkit-progress-value{transition:none}@media (prefers-reduced-motion:reduce){.toc-progress::-webkit-progress-value{transition:none}}[data-toc-panel]{scrollbar-width:thin;scrollbar-color:var(--rule) transparent;scrollbar-gutter:stable}[data-toc-panel]::-webkit-scrollbar{width:.5rem}[data-toc-panel]::-webkit-scrollbar-thumb{background:var(--rule);background-clip:padding-box;border:2px solid #0000}.toc-link{min-height:calc(var(--spacing) * 11);align-items:baseline;gap:calc(var(--spacing) * 2);border-left-style:var(--tw-border-style);padding-block:calc(var(--spacing) * 2.5);padding-left:calc(var(--spacing) * 3);color:var(--ink-2);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));--tw-duration:.15s;border-color:#0000;border-left-width:2px;text-decoration-line:none;transition-duration:.15s;display:flex}@media (hover:hover){.toc-link:hover{border-color:var(--rule-strong);color:var(--accent)}}.toc-link:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);--tw-ring-color:var(--accent);--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-offset-color:var(--paper);--tw-outline-style:none;outline-style:none}@media (min-width:64rem){.toc-link{min-height:calc(var(--spacing) * 10);padding-block:calc(var(--spacing) * 1.5)}}.toc-link[data-passed],.toc-link[data-passed]>span:first-child{color:var(--ink)}.toc-link[aria-current]{border-color:var(--accent);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--ink)}.toc-toggle-icon{opacity:1;filter:blur();transition-property:opacity,scale,filter;transition-duration:.15s;transition-timing-function:cubic-bezier(.2,0,0,1);scale:1}.toc-toggle-icon-close,[data-toc-toggle][aria-expanded=true] .toc-toggle-icon-menu{opacity:0;filter:blur(4px);scale:.25}[data-toc-toggle][aria-expanded=true] .toc-toggle-icon-close{opacity:1;filter:blur();scale:1}@media not all and (min-width:64rem){html.toc-panel-open{scrollbar-gutter:stable;overflow:hidden}.has-js [data-toc-panel][data-open=true]{height:calc(100dvh - var(--toc-panel-top,3rem));max-height:calc(100dvh - var(--toc-panel-top,3rem))}.has-js [data-toc-panel]:not([data-open=true]){display:none}}@media (max-width:40rem){.kv{display:block}.kv dt{margin-top:calc(var(--spacing) * 2)}.rating{align-items:stretch}.rating-prompt,.rating-note{flex-basis:100%}.rating-prompt{margin-bottom:var(--spacing)}.rating-actions{min-height:calc(var(--spacing) * 11)}.rating button[data-label]:after{inset-block:calc(var(--spacing) * -2)}.filters label,.filters input,.filters select{width:100%}}}@layer utilities{.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-x-0{inset-inline:0}.-inset-y-1{inset-block:calc(var(--spacing) * -1)}.-inset-y-1\.5{inset-block:calc(var(--spacing) * -1.5)}.-inset-y-2{inset-block:calc(var(--spacing) * -2)}.top-0{top:0}.top-1{top:var(--spacing)}.top-3{top:calc(var(--spacing) * 3)}.top-4{top:calc(var(--spacing) * 4)}.top-20{top:calc(var(--spacing) * 20)}.top-40{top:calc(var(--spacing) * 40)}.top-120{top:calc(var(--spacing) * 120)}.top-full{top:100%}.-bottom-px{bottom:-1px}.left-0{left:0}.left-3{left:calc(var(--spacing) * 3)}.z-20{z-index:20}.z-30{z-index:30}.z-50{z-index:50}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.m-0{margin:0}.mx-auto{margin-inline:auto}.my-4{margin-block:calc(var(--spacing) * 4)}.my-8{margin-block:calc(var(--spacing) * 8)}.my-12{margin-block:calc(var(--spacing) * 12)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-2\.5{margin-top:calc(var(--spacing) * 2.5)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-7{margin-top:calc(var(--spacing) * 7)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-10{margin-top:calc(var(--spacing) * 10)}.mt-12{margin-top:calc(var(--spacing) * 12)}.mt-14{margin-top:calc(var(--spacing) * 14)}.mt-16{margin-top:calc(var(--spacing) * 16)}.mt-auto{margin-top:auto}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.mb-9{margin-bottom:calc(var(--spacing) * 9)}.mb-10{margin-bottom:calc(var(--spacing) * 10)}.-ml-2{margin-left:calc(var(--spacing) * -2)}.-ml-px{margin-left:-1px}.ml-1{margin-left:var(--spacing)}.ml-4{margin-left:calc(var(--spacing) * 4)}.ml-auto{margin-left:auto}.line-clamp-1{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.table{display:table}.table-cell{display:table-cell}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-11{height:calc(var(--spacing) * 11)}.max-h-\[70vh\]{max-height:70vh}.max-h-\[72vh\]{max-height:72vh}.max-h-\[calc\(100vh-2rem\)\]{max-height:calc(100vh - 2rem)}.min-h-0{min-height:0}.min-h-8{min-height:calc(var(--spacing) * 8)}.min-h-10{min-height:calc(var(--spacing) * 10)}.min-h-11{min-height:calc(var(--spacing) * 11)}.min-h-12{min-height:calc(var(--spacing) * 12)}.min-h-24{min-height:calc(var(--spacing) * 24)}.min-h-\[68vh\]{min-height:68vh}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-11{width:calc(var(--spacing) * 11)}.w-14{width:calc(var(--spacing) * 14)}.w-20{width:calc(var(--spacing) * 20)}.w-60{width:calc(var(--spacing) * 60)}.w-64{width:calc(var(--spacing) * 64)}.w-\[13rem\]{width:13rem}.w-\[15rem\]{width:15rem}.w-full{width:100%}.max-w-7xl{max-width:var(--container-7xl)}.max-w-32{max-width:calc(var(--spacing) * 32)}.max-w-36{max-width:calc(var(--spacing) * 36)}.max-w-\[15rem\]{max-width:15rem}.max-w-\[58ch\]{max-width:58ch}.max-w-\[68ch\]{max-width:68ch}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:0}.min-w-10{min-width:calc(var(--spacing) * 10)}.min-w-52{min-width:calc(var(--spacing) * 52)}.min-w-\[13rem\]{min-width:13rem}.flex-1{flex:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.table-fixed{table-layout:fixed}.-translate-y-20{--tw-translate-y:calc(var(--spacing) * -20);translate:var(--tw-translate-x) var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.resize{resize:both}.scroll-mt-4{scroll-margin-top:calc(var(--spacing) * 4)}.scroll-mt-6{scroll-margin-top:calc(var(--spacing) * 6)}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-\[1fr_auto\]{grid-template-columns:1fr auto}.flex-col{flex-direction:column}.flex-nowrap{flex-wrap:nowrap}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-5{gap:calc(var(--spacing) * 5)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-2{column-gap:calc(var(--spacing) * 2)}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-x-6{column-gap:calc(var(--spacing) * 6)}.gap-y-1{row-gap:var(--spacing)}.gap-y-1\.5{row-gap:calc(var(--spacing) * 1.5)}.gap-y-3{row-gap:calc(var(--spacing) * 3)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-rule>:not(:last-child)){border-color:var(--rule)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-y-auto{overflow-y:auto}.overscroll-contain{overscroll-behavior:contain}.rounded-none{border-radius:0}.rounded-sm{border-radius:var(--radius-sm)}.rounded-l-none{border-top-left-radius:0;border-bottom-left-radius:0}.rounded-r-none{border-top-right-radius:0;border-bottom-right-radius:0}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-x-0{border-inline-style:var(--tw-border-style);border-inline-width:0}.border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.border-y-0{border-block-style:var(--tw-border-style);border-block-width:0}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-t-0{border-top-style:var(--tw-border-style);border-top-width:0}.border-t-2{border-top-style:var(--tw-border-style);border-top-width:2px}.border-t-\[3px\]{border-top-style:var(--tw-border-style);border-top-width:3px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-b-\[3px\]{border-bottom-style:var(--tw-border-style);border-bottom-width:3px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-double{--tw-border-style:double;border-style:double}.border-accent{border-color:var(--accent)}.border-ink{border-color:var(--ink)}.border-rule{border-color:var(--rule)}.border-rule-strong{border-color:var(--rule-strong)}.border-transparent{border-color:#0000}.bg-accent{background-color:var(--accent)}.bg-ink{background-color:var(--ink)}.bg-paper{background-color:var(--paper)}.bg-paper-2{background-color:var(--paper-2)}.bg-transparent{background-color:#0000}.fill-none{fill:none}.stroke-current{stroke:currentColor}.p-0{padding:0}.p-1{padding:var(--spacing)}.p-4{padding:calc(var(--spacing) * 4)}.px-0{padding-inline:0}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0{padding-block:0}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-16{padding-block:calc(var(--spacing) * 16)}.py-20{padding-block:calc(var(--spacing) * 20)}.pt-0{padding-top:0}.pt-1{padding-top:var(--spacing)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pt-5{padding-top:calc(var(--spacing) * 5)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pt-7{padding-top:calc(var(--spacing) * 7)}.pt-8{padding-top:calc(var(--spacing) * 8)}.pr-6{padding-right:calc(var(--spacing) * 6)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-7{padding-bottom:calc(var(--spacing) * 7)}.pb-9{padding-bottom:calc(var(--spacing) * 9)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-5{padding-left:calc(var(--spacing) * 5)}.pl-6{padding-left:calc(var(--spacing) * 6)}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.font-sans{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.font-serif{font-family:Newsreader,Newsreader Fallback Georgia,Newsreader Fallback Times,Newsreader Fallback Noto Serif,Newsreader Fallback DejaVu Serif,Iowan Old Style,Palatino Linotype,Georgia,serif}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[0\.8rem\]{font-size:.8rem}.text-\[0\.66rem\]{font-size:.66rem}.text-\[0\.68rem\]{font-size:.68rem}.text-\[0\.72rem\]{font-size:.72rem}.text-\[0\.95rem\]{font-size:.95rem}.text-\[1\.05rem\]{font-size:1.05rem}.leading-\[1\.1\]{--tw-leading:1.1;line-height:1.1}.leading-\[1\.2\]{--tw-leading:1.2;line-height:1.2}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[-0\.01em\]{--tw-tracking:-.01em;letter-spacing:-.01em}.tracking-\[-0\.02em\]{--tw-tracking:-.02em;letter-spacing:-.02em}.tracking-\[0\.1em\]{--tw-tracking:.1em;letter-spacing:.1em}.tracking-\[0\.08em\]{--tw-tracking:.08em;letter-spacing:.08em}.tracking-\[0\.12em\]{--tw-tracking:.12em;letter-spacing:.12em}.tracking-\[0\.15em\]{--tw-tracking:.15em;letter-spacing:.15em}.tracking-normal{--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal)}.text-wrap{text-wrap:wrap}.whitespace-nowrap{white-space:nowrap}.text-accent{color:var(--accent)}.text-down{color:var(--down)}.text-good{color:var(--good)}.text-ink{color:var(--ink)}.text-ink-2{color:var(--ink-2)}.text-loved{color:var(--loved)}.text-muted{color:var(--muted)}.text-paper{color:var(--paper)}.text-rule{color:var(--rule)}.text-warn{color:var(--warn)}.lowercase{text-transform:lowercase}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.no-underline{text-decoration-line:none}.underline{text-decoration-line:underline}.decoration-rule{-webkit-text-decoration-color:var(--rule);-webkit-text-decoration-color:var(--rule);text-decoration-color:var(--rule)}.underline-offset-4{text-underline-offset:4px}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_18px_32px_-26px_rgb\(0_0_0_\/_0\.6\)\]{--tw-shadow:0 18px 32px -26px var(--tw-shadow-color,#0009);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow\/backfill,.shadow\/compatibility,.shadow\/dry,.shadow\/maintenance{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-accent{--tw-ring-color:var(--accent)}.ring-offset-0{--tw-ring-offset-width:0px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.ring-offset-2{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.ring-offset-paper{--tw-ring-offset-color:var(--paper)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.grayscale{--tw-grayscale:grayscale(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (hover:hover){.group-hover\:text-accent:is(:where(.group):hover *){color:var(--accent)}.group-hover\:text-paper:is(:where(.group):hover *){color:var(--paper)}}.marker\:text-muted ::marker{color:var(--muted)}.marker\:text-muted::marker{color:var(--muted)}.marker\:text-muted ::-webkit-details-marker{color:var(--muted)}.marker\:text-muted::-webkit-details-marker{color:var(--muted)}@media (hover:hover){.hover\:border-accent:hover{border-color:var(--accent)}.hover\:bg-paper-2:hover{background-color:var(--paper-2)}.hover\:text-accent:hover{color:var(--accent)}.hover\:text-accent-hover:hover{color:var(--accent-hover)}.hover\:text-ink:hover{color:var(--ink)}.hover\:decoration-accent:hover{-webkit-text-decoration-color:var(--accent);-webkit-text-decoration-color:var(--accent);text-decoration-color:var(--accent)}}.focus\:translate-y-0:focus{--tw-translate-y:0px;translate:var(--tw-translate-x) var(--tw-translate-y)}.focus\:border-ink:focus{border-color:var(--ink)}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.active\:scale-\[0\.96\]:active{scale:.96}@media (min-width:40rem){.sm\:col-start-2{grid-column-start:2}.sm\:mt-12{margin-top:calc(var(--spacing) * 12)}.sm\:mt-14{margin-top:calc(var(--spacing) * 14)}.sm\:mt-16{margin-top:calc(var(--spacing) * 16)}.sm\:hidden{display:none}.sm\:inline{display:inline}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:gap-3{gap:calc(var(--spacing) * 3)}.sm\:gap-4{gap:calc(var(--spacing) * 4)}.sm\:px-6{padding-inline:calc(var(--spacing) * 6)}.sm\:py-4{padding-block:calc(var(--spacing) * 4)}.sm\:pt-6{padding-top:calc(var(--spacing) * 6)}.sm\:pr-8{padding-right:calc(var(--spacing) * 8)}.sm\:pl-6{padding-left:calc(var(--spacing) * 6)}.sm\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.sm\:text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}@media (min-width:48rem){.md\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}@media (min-width:64rem){.lg\:static{position:static}.lg\:sticky{position:sticky}.lg\:inset-x-auto{inset-inline:auto}.lg\:top-0{top:0}.lg\:top-6{top:calc(var(--spacing) * 6)}.lg\:z-10{z-index:10}.lg\:z-auto{z-index:auto}.lg\:mt-4{margin-top:calc(var(--spacing) * 4)}.lg\:mt-12{margin-top:calc(var(--spacing) * 12)}.lg\:block{display:block}.lg\:grid{display:grid}.lg\:hidden{display:none}.lg\:max-h-\[calc\(100dvh-3rem\)\]{max-height:calc(100dvh - 3rem)}.lg\:max-h-\[calc\(100vh-3rem\)\]{max-height:calc(100vh - 3rem)}.lg\:w-84{width:calc(var(--spacing) * 84)}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-\[16rem_minmax\(0\,1fr\)\]{grid-template-columns:16rem minmax(0,1fr)}.lg\:gap-x-10{column-gap:calc(var(--spacing) * 10)}.lg\:overflow-y-auto{overflow-y:auto}.lg\:border-0{border-style:var(--tw-border-style);border-width:0}.lg\:bg-paper{background-color:var(--paper)}.lg\:px-0{padding-inline:0}.lg\:px-6{padding-inline:calc(var(--spacing) * 6)}.lg\:pt-0{padding-top:0}.lg\:pr-3{padding-right:calc(var(--spacing) * 3)}.lg\:pb-3{padding-bottom:calc(var(--spacing) * 3)}.lg\:pb-10{padding-bottom:calc(var(--spacing) * 10)}.lg\:pl-0{padding-left:0}.lg\:shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}@media (min-width:80rem){.xl\:w-72{width:calc(var(--spacing) * 72)}.xl\:grid-cols-\[18rem_minmax\(0\,1fr\)\]{grid-template-columns:18rem minmax(0,1fr)}.xl\:gap-x-14{column-gap:calc(var(--spacing) * 14)}}.\[\&_\.comment-meta\]\:font-sans .comment-meta{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.\[\&_\.comment-meta\]\:text-sm .comment-meta{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.\[\&_\.comment-meta\]\:text-muted .comment-meta{color:var(--muted)}.\[\&_blockquote\.reply\]\:ml-6 blockquote.reply{margin-left:calc(var(--spacing) * 6)}.\[\&\:\:-webkit-details-marker\]\:hidden::-webkit-details-marker{display:none}.\[\&\>p\:first-child\]\:first-letter\:float-left>p:first-child:first-letter{float:left}.\[\&\>p\:first-child\]\:first-letter\:mt-1>p:first-child:first-letter{margin-top:var(--spacing)}.\[\&\>p\:first-child\]\:first-letter\:mr-2>p:first-child:first-letter{margin-right:calc(var(--spacing) * 2)}.\[\&\>p\:first-child\]\:first-letter\:font-serif>p:first-child:first-letter{font-family:Newsreader,Newsreader Fallback Georgia,Newsreader Fallback Times,Newsreader Fallback Noto Serif,Newsreader Fallback DejaVu Serif,Iowan Old Style,Palatino Linotype,Georgia,serif}.\[\&\>p\:first-child\]\:first-letter\:text-\[4\.6rem\]>p:first-child:first-letter{font-size:4.6rem}.\[\&\>p\:first-child\]\:first-letter\:leading-\[0\.72\]>p:first-child:first-letter{--tw-leading:.72;line-height:.72}.\[\&\>p\:first-child\]\:first-letter\:font-semibold>p:first-child:first-letter{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}}@font-face{font-family:Newsreader;font-style:normal;font-weight:200 800;font-stretch:100%;font-display:swap;src:url(/static/Newsreader.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Newsreader;font-style:italic;font-weight:200 800;font-stretch:100%;font-display:swap;src:url(/static/Newsreader-italic.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Newsreader Fallback Georgia;src:local(Georgia);size-adjust:93.88%;ascent-override:78.29%;descent-override:28.23%;line-gap-override:0%}@font-face{font-family:Newsreader Fallback Times;src:local(Times New Roman),local(Liberation Serif),local(Tinos);size-adjust:103.02%;ascent-override:71.35%;descent-override:25.72%;line-gap-override:0%}@font-face{font-family:Newsreader Fallback Noto Serif;src:local(Noto Serif);size-adjust:87.01%;ascent-override:84.48%;descent-override:30.46%;line-gap-override:0%}@font-face{font-family:Newsreader Fallback DejaVu Serif;src:local(DejaVu Serif);size-adjust:81.01%;ascent-override:90.73%;descent-override:32.71%;line-gap-override:0%}:root{--paper:#f6f3ec;--paper-2:#ece7db;--ink:#1c1b18;--ink-2:#4f4b43;--muted:#6b665a;--rule:#d8d2c4;--rule-strong:#1c1b18;--accent:#a3231f;--accent-hover:#7c1a16;--loved:#2f6f46;--good:#2f6a8f;--down:#9c3f36;--warn:#7d631c;color-scheme:light}@media (prefers-color-scheme:dark){:root:not([data-theme=light]){--paper:#151513;--paper-2:#1e1d1a;--ink:#ebe6da;--ink-2:#bfb9aa;--muted:#8f8a7d;--rule:#3a3833;--rule-strong:#ebe6da;--accent:#ef8c82;--accent-hover:#f7aaa2;--loved:#7fcb92;--good:#7fb8d8;--down:#ea8f84;--warn:#d9b45a;color-scheme:dark}}:root[data-theme=dark]{--paper:#151513;--paper-2:#1e1d1a;--ink:#ebe6da;--ink-2:#bfb9aa;--muted:#8f8a7d;--rule:#3a3833;--rule-strong:#ebe6da;--accent:#ef8c82;--accent-hover:#f7aaa2;--loved:#7fcb92;--good:#7fb8d8;--down:#ea8f84;--warn:#d9b45a;color-scheme:dark}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false} \ No newline at end of file diff --git a/src/web/tailwind.css b/src/web/tailwind.css index bfdd0a4..15e6828 100644 --- a/src/web/tailwind.css +++ b/src/web/tailwind.css @@ -151,7 +151,7 @@ .badge { @apply inline-flex items-center whitespace-nowrap rounded-full px-2 py-0.5 font-sans text-xs font-medium leading-5 tabular-nums; color:var(--ink-2); background:color-mix(in oklab, var(--ink) 8%, transparent); } .badge.selected, .badge.loved, .badge.ok { color:var(--loved); background:color-mix(in oklab, var(--loved) 14%, transparent); } .badge.good, .badge.assessed, .badge.triaged, .badge.degraded { color:var(--good); background:color-mix(in oklab, var(--good) 14%, transparent); } - .badge.down, .badge.excluded, .badge.failed, .badge.dry_run { color:var(--down); background:color-mix(in oklab, var(--down) 14%, transparent); } + .badge.down, .badge.slop, .badge.excluded, .badge.failed, .badge.dry_run { color:var(--down); background:color-mix(in oklab, var(--down) 14%, transparent); } .badge.shortlisted, .badge.admitted, .badge.eligible, .badge.cleared, .badge.reason, .badge.running, .badge.requested { color:var(--muted); background:color-mix(in oklab, var(--muted) 14%, transparent); } .badge.restart, .badge.warn { color:var(--warn); background:color-mix(in oklab, var(--warn) 16%, transparent); } @@ -196,7 +196,7 @@ .rating button[data-label]:not(.clear) { @apply -ml-px rounded-none border-rule bg-transparent px-2 py-1 text-ink-2 first:ml-0 first:rounded-l-sm last:rounded-r-sm hover:z-10 hover:border-ink hover:bg-paper-2 hover:text-ink; } .rating button.active[data-label="loved"] { @apply z-10 border-loved text-loved; background:color-mix(in oklab, var(--loved) 14%, transparent); } .rating button.active[data-label="good"] { @apply z-10 border-good text-good; background:color-mix(in oklab, var(--good) 14%, transparent); } - .rating button.active[data-label="down"] { @apply z-10 border-down text-down; background:color-mix(in oklab, var(--down) 14%, transparent); } + .rating button.active[data-label="down"], .rating button.active[data-label="slop"] { @apply z-10 border-down text-down; background:color-mix(in oklab, var(--down) 14%, transparent); } .rating button.clear { @apply invisible ml-1.5 border-0 bg-transparent px-1 text-muted underline decoration-rule underline-offset-4 hover:text-ink; } .rating:has(button[data-label]:not(.clear).active) button.clear, .rating button.clear.active { @apply visible; } .rating button.clear.active { @apply no-underline; } @@ -288,7 +288,7 @@ td .rating-note-label { @apply sr-only; } td .rating-note input { @apply text-xs; } /* the ratings table's verdict cell: one column, buttons then note, nothing wraps */ - .rating-cell .rating { @apply grid w-[15rem] grid-cols-1 gap-y-1.5; } + .rating-cell .rating { @apply grid w-[18rem] grid-cols-1 gap-y-1.5; } .rating-cell .rating-actions { @apply flex w-full min-h-0 items-center; } .rating-cell .rating button.clear { @apply ml-auto; } diff --git a/src/web/templates/_rating_widget.html b/src/web/templates/_rating_widget.html index 946789f..69c14ef 100644 --- a/src/web/templates/_rating_widget.html +++ b/src/web/templates/_rating_widget.html @@ -7,6 +7,7 @@ + {% if widget.show_note %}{% endif %} diff --git a/src/web/templates/_signals_table.html b/src/web/templates/_signals_table.html index b67ac1c..f42a9e9 100644 --- a/src/web/templates/_signals_table.html +++ b/src/web/templates/_signals_table.html @@ -1,7 +1,7 @@ {% if signals.empty %}

No signals recorded for this row (hygiene exclusion or thin telemetry).

{% else %}
{% for line in signals.lines %}{% endfor %}
signalrawnormweightpresent
{{ line.name }}{{ line.raw }}{{ line.norm }}{{ line.weight }}{% if line.present %}yes{% else %}absent{% endif %}
-

Preliminary blend {{ signals.blend }}{% if let Some(cos) = signals.top1_cos %} · interest top-1 cosine {{ cos }}{% endif %}{% if signals.exploration %} · exploration{% endif %}{% if signals.auto_include %} · auto-include{% endif %}

+

Preliminary blend {{ signals.blend }}{% if let Some(cos) = signals.top1_cos %} · interest top-1 cosine {{ cos }}{% endif %}{% if signals.exploration %} · exploration{% endif %}{% if signals.auto_include %} · auto-include{% endif %}{% if signals.slop_author %} · slop author{% endif %}

{% if !signals.top_interests.is_empty() %}

Top interests

    {% for interest in signals.top_interests %}
  • {{ interest.name }} · z {{ interest.z }} · cos {{ interest.cos }}
  • {% endfor %}
{% endif %} {% if !signals.neighbours.is_empty() %}

Nearest rated neighbours

    {% for neighbour in signals.neighbours %}
  • {{ neighbour.label }} {{ neighbour.title }} · cos {{ neighbour.cos }}
  • {% endfor %}
{% endif %} {% if !signals.notes.is_empty() %}
    {% for note in signals.notes %}
  • {{ note }}
  • {% endfor %}
{% endif %} diff --git a/src/web/templates/dashboard/ratings.html b/src/web/templates/dashboard/ratings.html index 38d8c5a..71f186e 100644 --- a/src/web/templates/dashboard/ratings.html +++ b/src/web/templates/dashboard/ratings.html @@ -9,7 +9,7 @@
- +
@@ -34,10 +34,11 @@
  1. Prompt verdict block. The {{ how.verdicts_in_prompt }} most recent non-cleared verdicts, newest first, are written into every LLM call's system prompt as one line each (LOVED | title | feed | summary). Only the rank matters here — a verdict never ages out of this block, it is pushed out by newer ones. Tune curation.feedback.verdicts_in_prompt.
  2. Weekly learned adjustments. Every {{ how.rebuild_interval_days }} days the editor model rewrites the profile's "Learned adjustments" bullets from the {{ how.max_ratings_in_rebuild }} most recent non-cleared verdicts, including notes and deep-assessment facets. See the Profile page.
  3. -
  4. Rated-neighbour signal. Each verdict with an embedding is an example with weight value × 0.5^(age / {{ how.half_life_days }} days), where loved = {{ how.loved }}, good = {{ how.good }}, not for me = {{ how.not_for_me }}; ratings older than {{ how.lookback_days }} days are not loaded. A candidate's signal is the weighted mean cosine to its {{ how.neighbour_k }} nearest positive examples minus {{ how.negative_coefficient }} × the same over its nearest negative ones. The signal's preliminary weight ({{ how.knn_weight }}) is scaled by a gate that opens above {{ how.knn_floor }} embedded verdicts and is fully open at {{ how.knn_full }}. Tune curation.ranking.rating_half_life_days, knn_floor, knn_full, neighbour_k and weights.preliminary.knn.
  5. +
  6. Rated-neighbour signal. Each verdict with an embedding is an example with weight value × 0.5^(age / {{ how.half_life_days }} days), where loved = {{ how.loved }}, good = {{ how.good }}, not for me = {{ how.not_for_me }}, AI slop = {{ how.slop }}; ratings older than {{ how.lookback_days }} days are not loaded. A candidate's signal is the weighted mean cosine to its {{ how.neighbour_k }} nearest positive examples minus {{ how.negative_coefficient }} × the same over its nearest negative ones. The signal's preliminary weight ({{ how.knn_weight }}) is scaled by a gate that opens above {{ how.knn_floor }} embedded verdicts and is fully open at {{ how.knn_full }}. Tune curation.ranking.rating_half_life_days, knn_floor, knn_full, neighbour_k and weights.preliminary.knn.
  7. Feed affinity. The same decayed weight is credited to the rated article's direct feeds, split evenly; each feed's Beta-smoothed rate (up + 1) / (up + down + 2) becomes a candidate's signal (the mean over its rated direct feeds). Its weight ({{ how.feed_weight }}) is gated between {{ how.feed_floor }} and {{ how.feed_full }} attributable ratings. Tune curation.ranking.feed_floor, feed_full and weights.preliminary.feed.
  8. +
  9. Slop authors. An AI slop verdict is also a report against the article's author: while it is the article's current verdict, every candidate by that author (same normalized name, any feed, no age limit) has its preliminary blend and utility cut by {{ how.slop_author_penalty }}. Articles without a known author get only the ordinary negative rating. Tune curation.ranking.slop_author_penalty.
-

Clearing a verdict removes it from all four paths without deleting history; ratings are append-only.

+

Clearing a verdict removes it from all five paths without deleting history; ratings are append-only.

@@ -46,7 +47,7 @@ {% if tab == "events" %}
- + @@ -75,7 +76,7 @@ {% else %} - + diff --git a/tests/m4_epub.rs b/tests/m4_epub.rs index ab90737..a1ba08e 100644 --- a/tests/m4_epub.rs +++ b/tests/m4_epub.rs @@ -340,10 +340,17 @@ fn rating_links_carry_the_spec_token() { let loved = build::rating_token("integration-secret", date, 1, Vote::Loved); let good = build::rating_token("integration-secret", date, 1, Vote::Good); let down = build::rating_token("integration-secret", date, 1, Vote::NotForMe); + let slop = build::rating_token("integration-secret", date, 1, Vote::Slop); assert_eq!(loved.len(), 16); assert_ne!(loved, good); assert_ne!(good, down); - for (segment, token) in [("loved", loved), ("good", good), ("down", down)] { + assert_ne!(down, slop); + for (segment, token) in [ + ("loved", loved), + ("good", good), + ("down", down), + ("slop", slop), + ] { assert!(chapter.xhtml.contains(&format!( "https://daily.hallada.net/r/2026-08-15/1/{segment}?t={token}" ))); @@ -351,6 +358,7 @@ fn rating_links_carry_the_spec_token() { assert!(chapter.xhtml.contains("[ Loved it ]")); assert!(chapter.xhtml.contains("[ Good ]")); assert!(chapter.xhtml.contains("[ Not for me ]")); + assert!(chapter.xhtml.contains("[ AI slop ]")); } #[test]