diff --git a/cetba.c b/cetba.c
index 96fdeb0..ec4b3e8 100644
--- a/cetba.c
+++ b/cetba.c
@@ -1308,9 +1308,7 @@ static void draw_book_rail(GtkDrawingArea *area, cairo_t *cr,
int width, int height, gpointer data) {
const double t_end = (double)(BOOK_NODES - 1);
const Rgb rail = color_from_hex(app_theme.rail);
- const Rgb mauve = color_from_hex(app_theme.accent);
const Rgb muted = color_from_hex(app_theme.subtext);
- double hx, hy;
(void)area;
(void)width;
@@ -1323,13 +1321,9 @@ static void draw_book_rail(GtkDrawingArea *area, cairo_t *cr,
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
- book_point(0.0, &hx, &hy);
- draw_node_halo(cr, hx, hy, NODE_SIZE * 1.05,
- mauve.r, mauve.g, mauve.b, 0.18);
-
cairo_new_path(cr);
book_path(cr, 0.0, t_end);
- cairo_set_line_width(cr, 16);
+ cairo_set_line_width(cr, 12);
cairo_set_source_rgb(cr, rail.r, rail.g, rail.b);
cairo_stroke(cr);
diff --git a/exercise_common.c b/exercise_common.c
index f7315a6..fa93fce 100644
--- a/exercise_common.c
+++ b/exercise_common.c
@@ -4,6 +4,27 @@
/* Exercise page shell */
/* ------------------------------------------------------------------ */
+/* Exercise text would otherwise run the full width of a maximised window,
+ * which is tiring to read. Keep the body at a comfortable measure and centre
+ * it once there is room to spare; below that it still fills the page. */
+#define EX_BODY_MAX_WIDTH 880
+
+static void ex_body_clamp(GtkAdjustment *adj, GParamSpec *ps, gpointer data) {
+ GtkWidget *body = data;
+ double avail = gtk_adjustment_get_page_size(adj);
+
+ (void)ps;
+ if (avail < 1.0)
+ return;
+ if (avail < (double)EX_BODY_MAX_WIDTH) {
+ gtk_widget_set_halign(body, GTK_ALIGN_FILL);
+ gtk_widget_set_size_request(body, -1, -1);
+ } else {
+ gtk_widget_set_halign(body, GTK_ALIGN_CENTER);
+ gtk_widget_set_size_request(body, EX_BODY_MAX_WIDTH, -1);
+ }
+}
+
GtkWidget *ex_page_shell(const char *back_target, const char *title,
const char *subtitle, const char *btn_label,
GtkWidget **body_out, GtkWidget **feedback_out,
@@ -33,6 +54,9 @@ GtkWidget *ex_page_shell(const char *back_target, const char *title,
body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 14);
gtk_widget_set_vexpand(body, TRUE);
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body);
+ g_signal_connect(gtk_scrolled_window_get_hadjustment(
+ GTK_SCROLLED_WINDOW(scroll)),
+ "notify::page-size", G_CALLBACK(ex_body_clamp), body);
*body_out = body;
bottom = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
diff --git a/hw.c b/hw.c
index d4faa54..e5a58ac 100644
--- a/hw.c
+++ b/hw.c
@@ -181,10 +181,8 @@ void hw_adjust_notify(GtkAdjustment *adj, GParamSpec *ps,
void hw_render_rail_to(cairo_t *cr) {
const double t_end = (double)(HW_UNITS - 1);
- const Rgb mauve = color_from_hex(app_theme.accent);
const Rgb rail = color_from_hex(app_theme.rail);
const Rgb muted = color_from_hex(app_theme.subtext);
- double hx, hy;
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
@@ -192,13 +190,9 @@ void hw_render_rail_to(cairo_t *cr) {
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
- hw_point(0.0, &hx, &hy);
- draw_node_halo(cr, hx, hy, NODE_SIZE * 1.05,
- mauve.r, mauve.g, mauve.b, 0.18);
-
cairo_new_path(cr);
hw_path(cr, 0.0, t_end);
- cairo_set_line_width(cr, 16);
+ cairo_set_line_width(cr, 12);
cairo_set_source_rgb(cr, rail.r, rail.g, rail.b);
cairo_stroke(cr);
diff --git a/i18n.c b/i18n.c
index b469631..f28b3b3 100644
--- a/i18n.c
+++ b/i18n.c
@@ -1454,20 +1454,11 @@ void i18n_bind(GtkWidget *widget, const char *key, int kind) {
}
void refresh_welcome_heading(void) {
- char *markup;
-
if (!welcome_heading)
return;
- if (app_lang == LANG_EN)
- markup = g_strdup_printf(
- "Welcome to maturita.C!",
- app_theme.accent);
- else
- markup = g_strdup_printf(
- "Vítejte ve maturita.C!",
- app_theme.accent);
- gtk_label_set_markup(GTK_LABEL(welcome_heading), markup);
- g_free(markup);
+ gtk_label_set_text(GTK_LABEL(welcome_heading),
+ app_lang == LANG_EN ? "Welcome to maturita.C"
+ : "Vítejte v maturita.C");
}
void refresh_stats_ui(void);
diff --git a/maturita.h b/maturita.h
index 604bc51..7c833d1 100644
--- a/maturita.h
+++ b/maturita.h
@@ -883,9 +883,6 @@ gboolean on_window_key_pressed(GtkEventControllerKey *controller,
GdkModifierType state,
gpointer user_data);
GtkWidget *build_welcome_page(void);
-void draw_node_halo(cairo_t *cr, double cx, double cy,
- double radius, double r, double g, double b,
- double alpha);
void draw_finish_cell(GtkDrawingArea *area, cairo_t *cr,
int width, int height, gpointer data);
void road_point(double t, double *ox, double *oy);
diff --git a/navigation.c b/navigation.c
index ed03392..5641a3c 100644
--- a/navigation.c
+++ b/navigation.c
@@ -95,34 +95,42 @@ gboolean on_window_key_pressed(GtkEventControllerKey *controller,
GtkWidget *build_welcome_page(void) {
GtkWidget *box;
+ GtkWidget *icon;
GtkWidget *heading;
- GtkWidget *card;
+ GtkWidget *body;
GtkWidget *button;
- box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 18);
+ box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_halign(box, GTK_ALIGN_CENTER);
gtk_widget_set_valign(box, GTK_ALIGN_CENTER);
gtk_widget_set_margin_top(box, 40);
gtk_widget_set_margin_bottom(box, 40);
+ icon = gtk_image_new_from_icon_name(ICON_NAME);
+ gtk_image_set_pixel_size(GTK_IMAGE(icon), 88);
+ gtk_widget_set_halign(icon, GTK_ALIGN_CENTER);
+ gtk_widget_set_margin_bottom(icon, 22);
+ gtk_box_append(GTK_BOX(box), icon);
+
heading = gtk_label_new(NULL);
welcome_heading = heading;
gtk_widget_set_halign(heading, GTK_ALIGN_CENTER);
gtk_widget_add_css_class(heading, "heading");
gtk_box_append(GTK_BOX(box), heading);
- card = gtk_label_new(NULL);
- i18n_bind(card, "welcome_body", 0);
- gtk_label_set_justify(GTK_LABEL(card), GTK_JUSTIFY_CENTER);
- gtk_label_set_wrap(GTK_LABEL(card), TRUE);
- gtk_label_set_max_width_chars(GTK_LABEL(card), 48);
- gtk_widget_add_css_class(card, "card");
- gtk_box_append(GTK_BOX(box), card);
+ body = gtk_label_new(NULL);
+ i18n_bind(body, "welcome_body", 0);
+ gtk_label_set_justify(GTK_LABEL(body), GTK_JUSTIFY_CENTER);
+ gtk_label_set_wrap(GTK_LABEL(body), TRUE);
+ gtk_label_set_max_width_chars(GTK_LABEL(body), 46);
+ gtk_widget_set_margin_top(body, 10);
+ gtk_widget_add_css_class(body, "welcome-body");
+ gtk_box_append(GTK_BOX(box), body);
button = gtk_button_new();
i18n_bind(button, "continue", 1);
gtk_widget_set_halign(button, GTK_ALIGN_CENTER);
- gtk_widget_set_margin_top(button, 6);
+ gtk_widget_set_margin_top(button, 28);
gtk_widget_add_css_class(button, "btn-primary");
gtk_box_append(GTK_BOX(box), button);
diff --git a/net.c b/net.c
index f81a3e9..4d7354d 100644
--- a/net.c
+++ b/net.c
@@ -394,10 +394,8 @@ void net_adjust_notify(GtkAdjustment *adj, GParamSpec *ps,
void net_render_rail_to(cairo_t *cr) {
const double t_end = (double)(NET_UNITS - 1);
- const Rgb mauve = color_from_hex(app_theme.accent);
const Rgb rail = color_from_hex(app_theme.rail);
const Rgb muted = color_from_hex(app_theme.subtext);
- double hx, hy;
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
cairo_paint(cr);
@@ -405,13 +403,9 @@ void net_render_rail_to(cairo_t *cr) {
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
- net_point(0.0, &hx, &hy);
- draw_node_halo(cr, hx, hy, NODE_SIZE * 1.05,
- mauve.r, mauve.g, mauve.b, 0.18);
-
cairo_new_path(cr);
net_path(cr, 0.0, t_end);
- cairo_set_line_width(cr, 16);
+ cairo_set_line_width(cr, 12);
cairo_set_source_rgb(cr, rail.r, rail.g, rail.b);
cairo_stroke(cr);
diff --git a/roadmap.c b/roadmap.c
index 22e99f9..bf902e5 100644
--- a/roadmap.c
+++ b/roadmap.c
@@ -4,19 +4,6 @@
/* Roadmap page */
/* ------------------------------------------------------------------ */
-void draw_node_halo(cairo_t *cr, double cx, double cy,
- double radius, double r, double g, double b,
- double alpha) {
- cairo_pattern_t *grad;
- grad = cairo_pattern_create_radial(cx, cy, 6.0, cx, cy, radius);
- cairo_pattern_add_color_stop_rgba(grad, 0.0, r, g, b, alpha);
- cairo_pattern_add_color_stop_rgba(grad, 0.55, r, g, b, alpha * 0.30);
- cairo_pattern_add_color_stop_rgba(grad, 1.0, r, g, b, 0.0);
- cairo_set_source(cr, grad);
- cairo_paint(cr);
- cairo_pattern_destroy(grad);
-}
-
/* Draw the checkered "finish line" node: checkerboard behind the unit
* number and the same lock glyph the locked units use. */
void draw_finish_cell(GtkDrawingArea *area, cairo_t *cr,
@@ -236,13 +223,9 @@ void draw_rail(GtkDrawingArea *area, cairo_t *cr,
int width, int height, gpointer user_data) {
const double t_lit = (double)(NUM_UNLOCKED - 1);
const double t_end = (double)(NUM_UNITS - 1);
- const double x0 = ROAD_MX;
- const double x1 = (double)road_cw - ROAD_MX;
- const Rgb mauve = color_from_hex(app_theme.accent);
- const Rgb blue = color_from_hex(app_theme.accent3);
+ const Rgb accent = color_from_hex(app_theme.accent);
const Rgb rail = color_from_hex(app_theme.rail);
const Rgb muted = color_from_hex(app_theme.subtext);
- double hx, hy;
(void)area;
(void)width;
@@ -255,41 +238,18 @@ void draw_rail(GtkDrawingArea *area, cairo_t *cr,
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
- road_point((double)(NUM_UNLOCKED - 1), &hx, &hy);
- draw_node_halo(cr, hx, hy, NODE_SIZE * 1.05,
- mauve.r, mauve.g, mauve.b, 0.18);
-
cairo_new_path(cr);
road_path(cr, 0.0, t_end);
- cairo_set_line_width(cr, 16);
+ cairo_set_line_width(cr, 12);
cairo_set_source_rgb(cr, rail.r, rail.g, rail.b);
cairo_stroke(cr);
if (t_lit > 0.0) {
- cairo_pattern_t *grad;
-
cairo_new_path(cr);
road_path(cr, 0.0, t_lit);
-
- grad = cairo_pattern_create_linear(x0, 0.0, x1, 0.0);
- cairo_pattern_add_color_stop_rgba(grad, 0.0,
- mauve.r, mauve.g, mauve.b, 0.16);
- cairo_pattern_add_color_stop_rgba(grad, 1.0,
- blue.r, blue.g, blue.b, 0.16);
- cairo_set_source(cr, grad);
- cairo_set_line_width(cr, 34);
- cairo_stroke_preserve(cr);
- cairo_pattern_destroy(grad);
-
- grad = cairo_pattern_create_linear(x0, 0.0, x1, 0.0);
- cairo_pattern_add_color_stop_rgba(grad, 0.0,
- mauve.r, mauve.g, mauve.b, 1.0);
- cairo_pattern_add_color_stop_rgba(grad, 1.0,
- blue.r, blue.g, blue.b, 1.0);
- cairo_set_source(cr, grad);
- cairo_set_line_width(cr, 16);
- cairo_stroke_preserve(cr);
- cairo_pattern_destroy(grad);
+ cairo_set_source_rgb(cr, accent.r, accent.g, accent.b);
+ cairo_set_line_width(cr, 12);
+ cairo_stroke(cr);
}
{
diff --git a/stats.c b/stats.c
index b7d27e4..dc31b9f 100644
--- a/stats.c
+++ b/stats.c
@@ -45,6 +45,17 @@ void progress_for_units(int first, int n, ProgressSum *out) {
}
}
+/* GTK gives the progress node a minimum width, so a fraction of zero would
+ * still paint a short stub of accent colour. Mark those bars so the
+ * stylesheet can hide the fill entirely. */
+static void stats_set_fraction(GtkWidget *bar, double fraction) {
+ gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(bar), fraction);
+ if (fraction > 0.0)
+ gtk_widget_remove_css_class(bar, "empty");
+ else
+ gtk_widget_add_css_class(bar, "empty");
+}
+
void refresh_stats_ui(void) {
ProgressSum all = {0};
int pct;
@@ -77,9 +88,10 @@ void refresh_stats_ui(void) {
gtk_label_set_text(GTK_LABEL(stats_ui.units_value), tmp);
g_free(tmp);
- gtk_progress_bar_set_fraction(
- GTK_PROGRESS_BAR(stats_ui.overall_bar),
- all.total_ex > 0 ? (double)all.done_ex / (double)all.total_ex : 0.0);
+ stats_set_fraction(stats_ui.overall_bar,
+ all.total_ex > 0
+ ? (double)all.done_ex / (double)all.total_ex
+ : 0.0);
for (int s = 0; s < NUM_SUBJECTS; s++) {
GtkWidget *count = stats_ui.subj[s].count;
@@ -100,13 +112,13 @@ void refresh_stats_ui(void) {
tmp = g_strdup_printf(tr("stats_ex_fmt"), sp.done_ex, sp.total_ex);
gtk_label_set_text(GTK_LABEL(count), tmp);
g_free(tmp);
- gtk_progress_bar_set_fraction(
- GTK_PROGRESS_BAR(bar),
- sp.total_ex > 0 ? (double)sp.done_ex / (double)sp.total_ex
- : 0.0);
+ stats_set_fraction(bar,
+ sp.total_ex > 0
+ ? (double)sp.done_ex / (double)sp.total_ex
+ : 0.0);
} else {
gtk_label_set_text(GTK_LABEL(count), tr("stats_locked"));
- gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(bar), 0.0);
+ stats_set_fraction(bar, 0.0);
}
}
@@ -130,7 +142,7 @@ void refresh_stats_ui(void) {
if (!unlocked) {
gtk_widget_add_css_class(row, "locked");
gtk_label_set_text(GTK_LABEL(count), tr("stats_locked"));
- gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(bar), 0.0);
+ stats_set_fraction(bar, 0.0);
if (badge)
gtk_widget_set_visible(badge, FALSE);
continue;
@@ -139,9 +151,8 @@ void refresh_stats_ui(void) {
tmp = g_strdup_printf(tr("stats_ex_fmt"), d, u->n_ex);
gtk_label_set_text(GTK_LABEL(count), tmp);
g_free(tmp);
- gtk_progress_bar_set_fraction(
- GTK_PROGRESS_BAR(bar),
- u->n_ex > 0 ? (double)d / (double)u->n_ex : 0.0);
+ stats_set_fraction(bar,
+ u->n_ex > 0 ? (double)d / (double)u->n_ex : 0.0);
if (complete) {
gtk_widget_add_css_class(row, "done");
@@ -328,6 +339,9 @@ GtkWidget *build_stats_page(void) {
summary = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10);
gtk_widget_add_css_class(summary, "stats-summary");
gtk_widget_set_halign(summary, GTK_ALIGN_FILL);
+ /* Equal columns; hexpand alone only shares the leftover space, which
+ * leaves the cards at different widths. */
+ gtk_box_set_homogeneous(GTK_BOX(summary), TRUE);
gtk_box_append(GTK_BOX(page), summary);
gtk_box_append(GTK_BOX(summary),
diff --git a/style.css b/style.css
index 2a51d6a..6167f6c 100644
--- a/style.css
+++ b/style.css
@@ -1,153 +1,27 @@
+/* Interface stylesheet.
+ *
+ * theme.c prepends the @define-color bindings of the active palette before
+ * this file is parsed, so nothing here names a literal colour: the rules
+ * describe shape, spacing and type only, and every palette stays swappable.
+ *
+ * Keep to the scales below when adding rules.
+ *
+ * type 12 caption | 13 small | 15 body | 17 lead | 20 26 30 headings
+ * weight 400 body | 500 emphasis | 600 controls and labels | 700 headings
+ * radius 8 controls | 12 rows and cards | 16 popovers | 999 circles
+ * motion 120ms colour | 150ms elevation
+ *
+ * Fills are flat and elevation is neutral; accent colour marks state, never
+ * decoration. Rules below the no-scale marker at the end of the file keep a
+ * fixed font size while the rest grows with the window.
+ */
+
+/* ------------------------------------------------------------------ */
+/* Window chrome */
+/* ------------------------------------------------------------------ */
+
window {
background-color: @bg_base;
- background-image: linear-gradient(160deg, @bg_crust 0%, @bg_base 40%, @bg_surface0 100%);
-}
-button {
- background-image: none;
-}
-.app-title {
- color: @fg_text;
- font-weight: 700;
- font-size: 14px;
-}
-.settings-btn,
-.settings-btn:hover,
-.settings-btn:active,
-.settings-btn:checked,
-.settings-btn:focus,
-.settings-btn:focus-visible {
- min-width: 34px;
- min-height: 34px;
- padding: 0;
- border-radius: 999px;
- background: transparent;
- background-color: transparent;
- background-image: none;
- border: none;
- outline: none;
- box-shadow: none;
- color: @fg_text;
-}
-.settings-btn:hover {
- color: @accent;
- background-color: alpha(@bg_surface0, 0.55);
-}
-.settings-btn:active {
- color: @accent;
- background-color: alpha(@bg_surface1, 0.4);
-}
-popover,
-popover.background,
-.settings-popover {
- background: @bg_mantle;
- background-color: @bg_mantle;
- color: @fg_text;
- border: 1px solid @bg_surface1;
- border-radius: 18px;
- box-shadow: 0 18px 40px alpha(@bg_crust, 0.45);
-}
-popover > contents,
-.settings-popover > contents {
- background: transparent;
- background-color: transparent;
- border: none;
- border-radius: 18px;
- box-shadow: none;
- padding: 0;
-}
-.settings-box {
- background-color: transparent;
- color: @fg_text;
- min-width: 292px;
- padding: 16px 16px 14px 16px;
-}
-.settings-title {
- color: @fg_text;
- font-size: 17px;
- font-weight: 800;
- letter-spacing: -0.2px;
-}
-.settings-label {
- color: @fg_overlay;
- font-size: 11px;
- font-weight: 700;
- letter-spacing: 0.8px;
-}
-.settings-seg {
- background-color: alpha(@bg_surface0, 0.55);
- border: none;
- border-radius: 12px;
- padding: 3px;
-}
-.mode-chip {
- background-image: none;
- background-color: transparent;
- color: @fg_subtext;
- border: none;
- border-radius: 10px;
- padding: 9px 12px;
- font-size: 13px;
- font-weight: 600;
- min-width: 0;
- box-shadow: none;
- transition: background-color 140ms ease, color 140ms ease,
- box-shadow 140ms ease;
-}
-.mode-chip:hover {
- background-color: alpha(@bg_surface1, 0.28);
- color: @fg_text;
-}
-.mode-chip:checked {
- background-image: linear-gradient(135deg, @accent 0%, @accent2 100%);
- color: @on_accent;
- font-weight: 800;
- box-shadow: 0 4px 12px alpha(@accent, 0.25);
-}
-.mode-chip:checked:hover {
- background-image: linear-gradient(135deg, @accent 0%, @accent2 100%);
- color: @on_accent;
-}
-.theme-grid {
- background-color: transparent;
- border: none;
- padding: 0;
-}
-flowboxchild {
- padding: 0;
- margin: 0;
- background: transparent;
- border: none;
- box-shadow: none;
-}
-.theme-card {
- background-image: none;
- background-color: transparent;
- color: @fg_text;
- border: none;
- border-radius: 12px;
- padding: 6px 4px;
- min-width: 0;
- box-shadow: none;
- transition: background-color 140ms ease;
-}
-.theme-card:hover {
- background-color: alpha(@bg_surface0, 0.45);
-}
-.theme-card:checked {
- background-color: transparent;
- box-shadow: none;
-}
-.theme-card:checked:hover {
- background-color: alpha(@bg_surface0, 0.35);
-}
-.theme-card-name {
- color: @fg_subtext;
- font-size: 11px;
- font-weight: 600;
-}
-.theme-card:checked .theme-card-name {
- color: @fg_text;
- font-weight: 700;
}
headerbar,
headerbar.titlebar,
@@ -155,325 +29,391 @@ headerbar.titlebar,
background-color: @bg_base;
background-image: none;
color: @fg_text;
- box-shadow: none;
border: none;
+ box-shadow: inset 0 -1px 0 alpha(@fg_text, 0.07);
}
-windowcontrols button:not(:hover) {
+.app-title {
color: @fg_text;
+ font-size: 13px;
+ font-weight: 600;
}
+windowcontrols button:not(:hover),
windowcontrols button:not(:hover) image {
+ color: @fg_subtext;
+}
+button {
+ background-image: none;
+}
+tooltip {
+ background-color: @bg_crust;
+ border: 1px solid alpha(@fg_text, 0.10);
+ border-radius: 8px;
color: @fg_text;
}
+
+/* Keyboard focus stays visible on every real control; the map nodes below
+ * are canvas items and opt out explicitly. */
+.btn-primary:focus-visible,
+.back-btn:focus-visible,
+.settings-btn:focus-visible,
+.pill:focus-visible,
+.chip:focus-visible,
+.group-btn:focus-visible,
+.mode-chip:focus-visible,
+.theme-card:focus-visible,
+.kahoot-opt:focus-visible {
+ outline-style: solid;
+ outline-width: 2px;
+ outline-color: alpha(@accent, 0.65);
+ outline-offset: 2px;
+}
+
+/* ------------------------------------------------------------------ */
+/* Type */
+/* ------------------------------------------------------------------ */
+
.heading {
color: @fg_text;
- font-size: 32px;
- font-weight: 800;
-}
-.card {
- background-color: alpha(@bg_surface0, 0.92);
- border: 1px solid @bg_surface1;
- border-radius: 18px;
- padding: 30px 34px;
- color: @fg_text;
- font-size: 16px;
-}
-.btn-primary {
- background-image: linear-gradient(135deg, @accent 0%, @accent2 100%);
- color: @on_accent;
- font-size: 16px;
+ font-size: 30px;
font-weight: 700;
- padding: 12px 40px;
- border: none;
- border-radius: 999px;
- box-shadow: 0 6px 18px alpha(@accent, 0.25);
- transition: box-shadow 150ms ease, background-image 150ms ease;
-}
-.btn-primary:hover {
- box-shadow: 0 8px 24px alpha(@accent, 0.45);
- background-image: linear-gradient(135deg, @accent2 0%, @accent3 100%);
-}
-.btn-primary:active {
- box-shadow: 0 3px 10px alpha(@accent, 0.35);
+ letter-spacing: -0.5px;
}
.roadmap-title {
color: @fg_text;
- font-size: 28px;
- font-weight: 800;
+ font-size: 26px;
+ font-weight: 700;
+ letter-spacing: -0.3px;
}
.roadmap-sub {
color: @fg_subtext;
- font-size: 14px;
+ font-size: 15px;
}
-.back-btn {
- min-width: 42px;
- min-height: 42px;
- padding: 0;
- border-radius: 999px;
- background-color: alpha(@bg_surface0, 0.9);
- border: 1px solid @bg_surface1;
- color: @fg_text;
- box-shadow: 0 4px 14px alpha(@bg_crust, 0.35);
- transition: background-color 150ms ease, color 150ms ease,
- border-color 150ms ease, box-shadow 150ms ease;
+.welcome-body {
+ color: @fg_subtext;
+ font-size: 15px;
}
-.back-btn:hover {
- background-color: @bg_surface1;
- border-color: @bg_surface2;
- color: @accent;
- box-shadow: 0 6px 20px alpha(@accent, 0.35);
-}
-.back-btn:active {
- background-color: @bg_surface0;
- box-shadow: 0 2px 8px alpha(@bg_crust, 0.35);
-}
-.unit-node {
- background-image: none;
- background-color: @node_bg;
- color: @fg_text;
- border: 2px solid @locked_border;
- border-radius: 999px;
- padding: 0;
- box-shadow: 0 4px 14px alpha(@bg_crust, 0.35);
- transition: transform 150ms ease, box-shadow 150ms ease,
- border-color 150ms ease;
-}
-.unit-node.done {
- background-image: linear-gradient(135deg, @success 0%, @success2 100%);
- border-color: @success;
- color: @on_accent;
- box-shadow: 0 4px 16px alpha(@success, 0.35);
-}
-.unit-node.current {
- background-image: linear-gradient(135deg, @accent 0%, @accent2 55%, @accent3 100%);
- border-color: @accent;
- color: @on_accent;
- box-shadow: 0 4px 18px alpha(@accent, 0.5),
- 0 0 0 4px alpha(@bg_base, 0.9),
- 0 0 0 7px alpha(@accent, 0.45);
-}
-.unit-node.done:hover,
-.unit-node.current:hover {
- transition: box-shadow 150ms ease, border-color 150ms ease;
-}
-.unit-node.done:hover {
- box-shadow: 0 8px 22px alpha(@success, 0.5);
-}
-.unit-node.current:hover {
- box-shadow: 0 8px 26px alpha(@accent, 0.65),
- 0 0 0 4px alpha(@bg_base, 0.9),
- 0 0 0 7px alpha(@accent, 0.55);
-}
-.unit-node.locked {
- background-image: none;
- background-color: @locked_bg;
- border: 2px solid @locked_border;
+.welcome-meta {
color: @fg_overlay;
- box-shadow: none;
+ font-size: 12px;
}
-.unit-node.locked:hover {
- transform: none;
- box-shadow: none;
-}
-.unit-node.finish {
- background-color: transparent;
- background-image: none;
- border: none;
- color: @fg_overlay;
- box-shadow: 0 4px 14px alpha(@bg_crust, 0.35);
-}
-.unit-node.finish:hover {
- transform: none;
- box-shadow: 0 4px 14px alpha(@bg_crust, 0.35);
-}
-.unit-node:focus,
-.unit-node:focus-visible,
-.unit-node:hover {
- outline: none;
-}
-.unit-number {
- font-size: 24px;
- font-weight: 800;
-}
-.unit-node.done .unit-number,
-.unit-node.current .unit-number {
- color: @on_accent;
-}
-.unit-node.locked .unit-number {
- color: @fg_overlay;
-}
-.state-icon {
- color: @on_accent;
-}
-.unit-node.locked .lock-icon {
- color: @bg_surface2;
-}
-.unit-name {
- color: @fg_text;
- font-size: 13px;
- font-weight: 600;
-}
-.unit-name-locked {
- color: @fg_overlay;
-}
-.ex-bubble {
- min-width: 64px;
- min-height: 64px;
- padding: 0;
- border-radius: 999px;
- background-color: @node_bg;
- color: @fg_text;
- border: 2px solid @locked_border;
- box-shadow: 0 4px 14px alpha(@bg_crust, 0.35);
- transition: border-color 150ms ease, box-shadow 150ms ease;
-}
-.ex-bubble:hover {
- background-image: none;
- border-color: @accent;
- box-shadow: 0 6px 20px alpha(@accent, 0.35);
-}
-.ex-bubble.done {
- background-image: linear-gradient(135deg, @success 0%, @success2 100%);
- border-color: @success;
- color: @on_accent;
- box-shadow: 0 4px 16px alpha(@success, 0.35);
-}
-.ex-bubble.done:hover {
- box-shadow: 0 8px 22px alpha(@success, 0.5);
-}
-.ex-bubble:focus,
-.ex-bubble:focus-visible {
- outline: none;
-}
-.ex-branch {
- border-style: dashed;
- border-color: @accent;
-}
-.ex-branch:hover {
- border-style: solid;
-}
-.bubble-number {
- font-size: 22px;
- font-weight: 800;
-}
-.ex-bubble.done .bubble-number {
- color: @on_accent;
-}
-.bubble-icon {
- color: @on_accent;
-}
-.ex-label {
- color: @fg_text;
+
+/* Small all-caps-ish section markers. */
+.settings-label,
+.stats-section,
+.stats-metric-label,
+.notes-kicker,
+.group-panel-label {
+ color: @fg_subtext;
font-size: 12px;
font-weight: 600;
}
-.cz-label {
- background-color: @bg_base;
- padding: 1px 6px;
- border-radius: 8px;
+.notes-kicker {
+ color: @accent;
+ letter-spacing: 0.6px;
}
-.book-card {
- background-image: none;
- background-color: alpha(@bg_surface0, 0.92);
- border: 1px solid @bg_surface1;
- border-radius: 18px;
- padding: 20px 26px;
+
+.hint,
+.meaning {
+ color: @fg_subtext;
+ font-size: 13px;
+}
+.ex-prompt {
color: @fg_text;
- box-shadow: 0 6px 18px alpha(@bg_crust, 0.22);
- transition: box-shadow 160ms ease, border-color 160ms ease,
- background-color 160ms ease;
+ font-size: 15px;
+ font-weight: 400;
}
-.book-card:hover {
- border-color: @accent;
- background-color: alpha(@accent, 0.10);
- box-shadow: 0 12px 30px alpha(@accent, 0.32);
+.ex-sub {
+ color: @fg_subtext;
+ font-size: 13px;
+ font-weight: 500;
}
-.book-card:active {
- background-color: alpha(@accent, 0.18);
- box-shadow: 0 4px 12px alpha(@accent, 0.25);
-}
-.reading-hero {
- opacity: 0.22;
-}
-.book-title {
+.trans-word {
color: @fg_text;
font-size: 24px;
- font-weight: 800;
+ font-weight: 600;
}
-.book-author {
- color: @accent2;
+.dlg-speaker {
+ color: @accent;
font-size: 15px;
+ font-weight: 600;
+}
+.number-big {
+ color: @fg_text;
+ font-size: 24px;
+ font-weight: 600;
+}
+.hm-word {
+ color: @fg_text;
+ font-family: monospace;
+ font-size: 26px;
+ font-weight: 600;
+ letter-spacing: 2px;
+}
+.chain {
+ color: @fg_text;
+ font-size: 17px;
+ font-weight: 500;
+ letter-spacing: 0.5px;
+}
+.u3-answer {
+ color: @success;
+ font-size: 13px;
+ font-weight: 600;
+}
+.feedback-ok {
+ color: @success;
+ font-size: 14px;
+ font-weight: 600;
+}
+.feedback-err {
+ color: @error;
+ font-size: 14px;
+ font-weight: 600;
+}
+.feedback-warn {
+ color: @warning;
+ font-size: 14px;
+ font-weight: 600;
+}
+
+/* ------------------------------------------------------------------ */
+/* Surfaces */
+/* ------------------------------------------------------------------ */
+
+.quiz-card,
+.notes-card,
+.stats-metric,
+.stats-unit-row,
+.book-card,
+.lit-link {
+ background-color: mix(@bg_base, @bg_surface0, 0.55);
+ background-image: none;
+ border: 1px solid alpha(@fg_text, 0.09);
+ border-radius: 12px;
+ color: @fg_text;
+ box-shadow: none;
+}
+.quiz-card {
+ padding: 16px 18px;
+}
+.notes-card {
+ padding: 22px 26px;
+}
+.notes-title {
+ color: @fg_text;
+ font-size: 20px;
font-weight: 700;
}
-.book-sub {
+.notes-body {
+ color: @fg_text;
+ font-size: 15px;
+}
+.notes-tip {
+ color: @success;
+ font-size: 14px;
+ font-weight: 500;
+}
+.group-panel,
+.sent-group {
+ background-color: alpha(@fg_text, 0.04);
+ border: 1px solid alpha(@fg_text, 0.09);
+ border-radius: 12px;
+ padding: 12px;
+}
+.sent-group.ok {
+ border-color: @success;
+}
+.sent-group.wrong {
+ border-color: @error;
+}
+
+popover,
+popover.background,
+.settings-popover {
+ background-color: @bg_mantle;
+ color: @fg_text;
+ border: 1px solid alpha(@fg_text, 0.12);
+ border-radius: 16px;
+ box-shadow: 0 12px 32px alpha(@bg_crust, 0.45);
+}
+popover > contents,
+.settings-popover > contents {
+ background-color: transparent;
+ border: none;
+ border-radius: 16px;
+ box-shadow: none;
+ padding: 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* Buttons */
+/* ------------------------------------------------------------------ */
+
+.btn-primary {
+ background-image: none;
+ background-color: @accent;
+ color: @on_accent;
+ font-size: 15px;
+ font-weight: 600;
+ padding: 10px 22px;
+ border: none;
+ border-radius: 8px;
+ box-shadow: none;
+ transition: background-color 120ms ease;
+}
+.btn-primary:hover {
+ background-color: shade(@accent, 1.1);
+}
+.btn-primary:active {
+ background-color: shade(@accent, 0.92);
+}
+.btn-primary:disabled {
+ background-color: alpha(@fg_text, 0.10);
+ color: @fg_overlay;
+}
+
+/* Flat icon buttons in the header bar and above each page. */
+.back-btn,
+.settings-btn,
+.settings-btn:hover,
+.settings-btn:active,
+.settings-btn:checked,
+.settings-btn:focus {
+ min-width: 32px;
+ min-height: 32px;
+ padding: 0;
+ border-radius: 8px;
+ background-color: transparent;
+ background-image: none;
+ border: none;
+ box-shadow: none;
+ color: @fg_subtext;
+ transition: background-color 120ms ease, color 120ms ease;
+}
+.back-btn:hover,
+.settings-btn:hover {
+ background-color: alpha(@fg_text, 0.09);
+ color: @fg_text;
+}
+.back-btn:active,
+.settings-btn:active {
+ background-color: alpha(@fg_text, 0.15);
+ color: @fg_text;
+}
+
+/* Word / answer chips. */
+.pill,
+.chip,
+.group-btn {
+ background-image: none;
+ background-color: mix(@bg_base, @bg_surface0, 0.7);
+ color: @fg_text;
+ border: 1px solid alpha(@fg_text, 0.12);
+ border-radius: 8px;
+ padding: 7px 14px;
+ font-size: 14px;
+ font-weight: 500;
+ box-shadow: none;
+ transition: background-color 120ms ease, border-color 120ms ease;
+}
+.pill:hover,
+.chip:hover,
+.group-btn:hover {
+ background-image: none;
+ background-color: mix(@bg_base, @bg_surface0, 1.0);
+ border-color: alpha(@accent, 0.7);
+}
+.pill:active,
+.chip:active,
+.group-btn:active {
+ background-image: none;
+ background-color: @bg_surface1;
+}
+.pill:checked,
+.group-btn:checked {
+ background-image: none;
+ background-color: @accent;
+ border-color: @accent;
+ color: @on_accent;
+ font-weight: 600;
+}
+.pill.ok,
+.pill.ok:checked,
+.pill.ok:hover {
+ background-image: none;
+ background-color: @success;
+ border-color: @success;
+ color: @on_accent;
+}
+.pill.wrong,
+.pill.wrong:checked,
+.pill.wrong:hover {
+ background-image: none;
+ background-color: @error;
+ border-color: @error;
+ color: @on_accent;
+}
+.pill.hm-key {
+ min-width: 32px;
+ padding: 5px 6px;
+ font-size: 13px;
+}
+.chip {
+ border-radius: 999px;
+}
+.chip.ghost-host {
+ opacity: 0;
+}
+.group-panel-label {
+ margin-bottom: 4px;
+}
+
+/* Multiple-choice rows read as list items rather than as chips. They are
+ * outlined instead of filled, so they do not have to be lighter than the card
+ * in dark mode and darker in light mode. */
+.quiz-pill {
+ background-color: transparent;
+ border-color: alpha(@fg_text, 0.13);
+ border-radius: 10px;
+ padding: 11px 14px;
+ min-height: 40px;
+}
+.quiz-pill label {
+ font-weight: 400;
+}
+.quiz-pill:checked label {
+ font-weight: 600;
+}
+.quiz-heading {
+ color: @fg_text;
+ font-size: 17px;
+ font-weight: 600;
+}
+.quiz-intro {
color: @fg_subtext;
font-size: 14px;
}
-.lit-link {
- background-image: none;
- background-color: alpha(@bg_surface0, 0.92);
- border: 1px solid @bg_surface1;
- border-radius: 16px;
- padding: 14px 18px;
+.quiz-q {
color: @fg_text;
- box-shadow: 0 5px 16px alpha(@bg_crust, 0.18);
- transition: box-shadow 160ms ease, border-color 160ms ease,
- background-color 160ms ease;
-}
-.lit-link:hover {
- border-color: @accent;
- background-color: alpha(@accent, 0.10);
- box-shadow: 0 10px 26px alpha(@accent, 0.30);
-}
-.lit-link:active {
- background-color: alpha(@accent, 0.18);
- box-shadow: 0 4px 12px alpha(@accent, 0.25);
-}
-.lit-link-title {
- color: @fg_text;
- font-size: 17px;
- font-weight: 800;
-}
-.lit-link-sub {
- color: @fg_subtext;
- font-size: 13px;
-}
-.lit-progress {
- color: @accent2;
- font-size: 13px;
- font-weight: 800;
- letter-spacing: 1px;
-}
-.lit-score {
- color: @fg_subtext;
- font-size: 13px;
- font-weight: 700;
-}
-.lit-prompt {
- color: @fg_text;
- font-size: 20px;
- font-weight: 800;
-}
-.lit-expl {
- color: @success2;
font-size: 15px;
font-weight: 600;
- background-color: alpha(@bg_surface0, 0.85);
- border-left: 4px solid @success;
- border-radius: 8px;
- padding: 10px 14px;
}
+.quiz-options {
+ margin-top: 4px;
+}
+
+/* Four-colour quiz board: the colours are the mechanic, so they stay, but
+ * they are flat and the answer state is shown by the border alone. */
.kahoot-opt {
background-image: none;
color: @on_accent;
font-size: 15px;
- font-weight: 700;
- padding: 16px;
- border: 3px solid transparent;
- border-radius: 14px;
- box-shadow: 0 4px 14px alpha(@bg_crust, 0.30);
-}
-.kahoot-opt:hover {
- box-shadow: 0 7px 22px alpha(@bg_crust, 0.42);
+ font-weight: 600;
+ padding: 14px 16px;
+ border: 2px solid transparent;
+ border-radius: 12px;
+ box-shadow: none;
+ transition: border-color 120ms ease, opacity 120ms ease;
}
.kahoot-0 {
background-color: @accent;
@@ -487,451 +427,444 @@ windowcontrols button:not(:hover) image {
.kahoot-3 {
background-color: @success;
}
+.kahoot-opt:hover {
+ border-color: alpha(@fg_text, 0.35);
+}
.kahoot-opt.ok {
border-color: @fg_text;
- box-shadow: 0 0 0 3px alpha(@fg_text, 0.35);
}
.kahoot-opt.wrong {
- opacity: 0.35;
-}
-.ex-prompt {
- color: @fg_text;
- font-size: 16px;
- font-weight: 500;
-}
-.trans-word {
- color: @fg_text;
- font-size: 24px;
- font-weight: 700;
-}
-.ex-sub {
- color: @fg_subtext;
- font-size: 13px;
- font-weight: 700;
-}
-.hint {
- color: @fg_subtext;
- font-size: 13px;
- font-style: italic;
-}
-.meaning {
- color: @fg_subtext;
- font-size: 13px;
- font-style: italic;
-}
-.u3-answer {
- color: @success;
- font-size: 13px;
- font-weight: 700;
-}
-.notes-card {
- background-color: alpha(@bg_surface0, 0.9);
- border: 1px solid @bg_surface1;
- border-radius: 24px;
- padding: 24px 34px;
- box-shadow: 0 10px 30px alpha(@bg_crust, 0.20);
-}
-.notes-kicker {
- color: @accent2;
- font-weight: 800;
- letter-spacing: 2px;
-}
-.notes-title {
- color: @fg_text;
- font-weight: 800;
-}
-.notes-body {
- color: @fg_text;
-}
-.notes-tip {
- color: @success2;
- font-weight: 700;
-}
-.dlg-speaker {
- color: @accent;
- font-weight: 700;
- font-size: 15px;
-}
-.number-big {
- color: @warning;
- font-size: 26px;
- font-weight: 800;
-}
-.hm-word {
- color: @fg_text;
- font-family: monospace;
- font-size: 30px;
- font-weight: 800;
-}
-.chain {
- color: @warning;
- font-size: 20px;
- font-weight: 700;
- letter-spacing: 1px;
+ opacity: 0.4;
}
+
+/* ------------------------------------------------------------------ */
+/* Text entry */
+/* ------------------------------------------------------------------ */
+
entry {
background-color: @bg_mantle;
color: @fg_text;
- border: 1px solid @bg_surface1;
- border-radius: 10px;
- padding: 8px 12px;
+ border: 1px solid alpha(@fg_text, 0.14);
+ border-radius: 8px;
+ padding: 7px 11px;
font-size: 15px;
caret-color: @accent;
+ box-shadow: none;
}
entry:focus {
border-color: @accent;
+ box-shadow: 0 0 0 2px alpha(@accent, 0.22);
+}
+entry.answer-ok {
+ border-color: @success;
+ background-color: alpha(@success, 0.10);
+}
+entry.answer-wrong {
+ border-color: @error;
+ background-color: alpha(@error, 0.10);
}
combobox {
- background-color: @bg_mantle;
+ background-color: transparent;
color: @fg_text;
}
combobox button {
background-image: none;
background-color: @bg_mantle;
color: @fg_text;
- border: 1px solid @bg_surface1;
- border-radius: 10px;
+ border: 1px solid alpha(@fg_text, 0.14);
+ border-radius: 8px;
padding: 4px 10px;
+ box-shadow: none;
}
combobox button:hover {
background-image: none;
- border-color: @accent;
+ border-color: alpha(@accent, 0.7);
}
combobox.answer-ok button {
border-color: @success;
- background-color: alpha(@success, 0.12);
+ background-color: alpha(@success, 0.10);
}
combobox.answer-wrong button {
border-color: @error;
- background-color: alpha(@error, 0.12);
+ background-color: alpha(@error, 0.10);
}
-entry.answer-ok {
- border-color: @success;
- background-color: alpha(@success, 0.08);
-}
-entry.answer-wrong {
- border-color: @error;
- background-color: alpha(@error, 0.08);
-}
-.pill {
+
+/* ------------------------------------------------------------------ */
+/* Progress maps */
+/* ------------------------------------------------------------------ */
+
+.unit-node,
+.ex-bubble {
background-image: none;
background-color: @node_bg;
color: @fg_text;
border: 2px solid @locked_border;
border-radius: 999px;
- padding: 6px 18px;
- font-size: 15px;
- transition: border-color 150ms ease, box-shadow 150ms ease,
- background-color 150ms ease;
-}
-.pill:hover {
- background-image: none;
- background-color: @node_bg;
- border-color: @accent;
+ padding: 0;
box-shadow: none;
+ transition: background-color 120ms ease, border-color 120ms ease,
+ box-shadow 150ms ease;
}
-.pill:active {
- background-image: none;
- background-color: @bg_surface1;
- box-shadow: none;
+.ex-bubble {
+ min-width: 64px;
+ min-height: 64px;
}
-.pill:checked {
- background-image: linear-gradient(135deg, @accent 0%, @accent2 100%);
- color: @on_accent;
- border-color: @accent;
- font-weight: 700;
-}
-.pill.ok,
-.pill.ok:checked {
- background-image: linear-gradient(135deg, @success 0%, @success2 100%);
- color: @on_accent;
+.unit-node.done,
+.ex-bubble.done {
+ background-color: @success;
border-color: @success;
- box-shadow: 0 0 0 2px alpha(@success, 0.35);
-}
-.pill.wrong,
-.pill.wrong:checked {
- background-image: linear-gradient(135deg, @error 0%, #c45c5c 100%);
color: @on_accent;
- border-color: @error;
- box-shadow: 0 0 0 2px alpha(@error, 0.35);
}
-.pill.hm-key {
- padding: 4px 5px;
- min-width: 32px;
+.unit-node.current {
+ background-color: @accent;
+ border-color: @accent;
+ color: @on_accent;
+ box-shadow: 0 0 0 4px alpha(@accent, 0.2);
+}
+.unit-node.locked {
+ background-color: @locked_bg;
+ border-color: @locked_border;
+ color: @fg_overlay;
+}
+.unit-node.finish {
+ background-color: transparent;
+ border: none;
+ color: @fg_overlay;
+}
+.unit-node:hover,
+.ex-bubble:hover {
+ border-color: @accent;
+}
+.unit-node.locked:hover {
+ border-color: @locked_border;
+}
+.unit-node.done:hover,
+.ex-bubble.done:hover {
+ border-color: shade(@success, 1.15);
+}
+.unit-node.current:hover {
+ box-shadow: 0 0 0 5px alpha(@accent, 0.3);
+}
+.unit-node:focus,
+.unit-node:focus-visible,
+.ex-bubble:focus,
+.ex-bubble:focus-visible {
+ outline-style: none;
+}
+.ex-branch {
+ border-style: dashed;
+ border-color: @accent;
+}
+.ex-branch:hover {
+ border-style: solid;
+}
+
+.unit-number {
+ font-size: 22px;
+ font-weight: 700;
+}
+.bubble-number {
+ font-size: 20px;
+ font-weight: 700;
+}
+.unit-node.done .unit-number,
+.unit-node.current .unit-number,
+.ex-bubble.done .bubble-number,
+.state-icon,
+.bubble-icon {
+ color: @on_accent;
+}
+.unit-node.locked .unit-number {
+ color: @fg_overlay;
+}
+.unit-node.locked .lock-icon {
+ color: @fg_overlay;
+}
+
+/* Node captions sit on top of the rail, so they carry the page background. */
+.unit-name,
+.ex-label {
+ color: @fg_text;
font-size: 13px;
-}
-.quiz-card {
- background-color: alpha(@bg_surface0, 0.85);
- border: 1px solid @bg_surface1;
- border-radius: 18px;
- padding: 16px 18px 14px 18px;
- box-shadow: 0 6px 18px alpha(@bg_crust, 0.18);
-}
-.quiz-heading {
- color: @fg_text;
- font-size: 18px;
- font-weight: 700;
-}
-.quiz-intro {
- color: @fg_subtext;
- font-size: 14px;
- font-style: italic;
-}
-.quiz-q {
- color: @fg_text;
- font-size: 16px;
- font-weight: 700;
-}
-.quiz-options {
- margin-top: 2px;
-}
-.quiz-pill {
- border-radius: 14px;
- padding: 12px 16px;
- min-height: 44px;
-}
-.quiz-pill label {
font-weight: 500;
}
-.quiz-pill:checked label {
+.unit-name-locked {
+ color: @fg_overlay;
+}
+.cz-label {
+ background-color: @bg_base;
+ border-radius: 6px;
+ padding: 2px 6px;
+}
+
+/* ------------------------------------------------------------------ */
+/* Reading list and literature */
+/* ------------------------------------------------------------------ */
+
+.book-card,
+.lit-link {
+ padding: 16px 20px;
+ transition: background-color 120ms ease, border-color 120ms ease;
+}
+.book-card:hover,
+.lit-link:hover {
+ background-color: mix(@bg_base, @bg_surface0, 0.9);
+ border-color: alpha(@accent, 0.6);
+}
+.book-card:active,
+.lit-link:active {
+ background-color: alpha(@accent, 0.14);
+}
+.reading-hero {
+ opacity: 0.18;
+}
+.book-title {
+ color: @fg_text;
+ font-size: 20px;
font-weight: 700;
}
-.chip {
- background-image: none;
- background-color: @bg_surface1;
- color: @fg_text;
- border: 1px solid @bg_surface2;
- border-radius: 999px;
- padding: 6px 14px;
- font-size: 14px;
- font-weight: 600;
- transition: background-color 150ms ease, border-color 150ms ease;
+.book-author {
+ color: @fg_subtext;
+ font-size: 15px;
+ font-weight: 500;
}
-.chip:hover {
- background-image: none;
- background-color: @bg_surface2;
- border-color: @accent;
- box-shadow: none;
-}
-.chip:active {
- background-image: none;
- background-color: @bg_surface2;
- box-shadow: none;
-}
-.chip.ghost-host {
- opacity: 0;
-}
-.group-btn {
- background-image: none;
- background-color: @node_bg;
- color: @fg_text;
- border: 2px solid @locked_border;
- border-radius: 12px;
- padding: 8px 18px;
- font-size: 14px;
- font-weight: 700;
- transition: border-color 150ms ease, box-shadow 150ms ease;
-}
-.group-btn:hover {
- background-image: none;
- background-color: @node_bg;
- border-color: @accent;
- box-shadow: none;
-}
-.group-btn:active {
- background-image: none;
- background-color: @bg_surface1;
- box-shadow: none;
-}
-.group-btn:checked {
- background-image: linear-gradient(135deg, @accent3 0%, @success2 100%);
- color: @on_accent;
- border-color: @accent3;
-}
-.group-panel {
- background-color: alpha(@bg_surface0, 0.5);
- border: 2px dashed @bg_surface1;
- border-radius: 14px;
- padding: 10px;
-}
-.group-panel-label {
+.book-sub,
+.lit-link-sub {
color: @fg_subtext;
font-size: 13px;
+}
+.lit-link-title {
+ color: @fg_text;
+ font-size: 17px;
+ font-weight: 600;
+}
+.lit-progress {
+ color: @accent;
+ font-size: 13px;
+ font-weight: 600;
+}
+.lit-score {
+ color: @fg_subtext;
+ font-size: 13px;
+ font-weight: 500;
+}
+.lit-prompt {
+ color: @fg_text;
+ font-size: 17px;
+ font-weight: 600;
+}
+.lit-expl {
+ color: @fg_text;
+ font-size: 14px;
+ background-color: alpha(@success, 0.10);
+ border-left: 3px solid @success;
+ border-radius: 6px;
+ padding: 10px 14px;
+}
+
+/* ------------------------------------------------------------------ */
+/* Settings popover */
+/* ------------------------------------------------------------------ */
+
+.settings-box {
+ background-color: transparent;
+ color: @fg_text;
+ min-width: 292px;
+ padding: 16px;
+}
+.settings-title {
+ color: @fg_text;
+ font-size: 17px;
font-weight: 700;
}
-.sent-group {
- background-color: alpha(@bg_surface0, 0.5);
- border: 1px solid @bg_surface1;
- border-radius: 14px;
- padding: 12px;
+.settings-seg {
+ background-color: alpha(@fg_text, 0.06);
+ border: none;
+ border-radius: 8px;
+ padding: 3px;
}
-.sent-group.ok {
- border-color: @success;
+.mode-chip {
+ background-image: none;
+ background-color: transparent;
+ color: @fg_subtext;
+ border: none;
+ border-radius: 6px;
+ padding: 7px 12px;
+ font-size: 13px;
+ font-weight: 500;
+ min-width: 0;
+ box-shadow: none;
+ transition: background-color 120ms ease, color 120ms ease;
}
-.sent-group.wrong {
- border-color: @error;
+.mode-chip:hover {
+ background-color: alpha(@fg_text, 0.07);
+ color: @fg_text;
}
-.feedback-ok {
- color: @success;
- font-size: 15px;
- font-weight: 700;
+.mode-chip:checked,
+.mode-chip:checked:hover {
+ background-image: none;
+ background-color: @accent;
+ color: @on_accent;
+ font-weight: 600;
}
-.feedback-err {
- color: @error;
- font-size: 15px;
- font-weight: 700;
+.theme-grid,
+flowboxchild {
+ background-color: transparent;
+ border: none;
+ box-shadow: none;
+ padding: 0;
+ margin: 0;
}
-.feedback-warn {
- color: @warning;
- font-size: 15px;
- font-weight: 700;
+.theme-card {
+ background-image: none;
+ background-color: transparent;
+ color: @fg_text;
+ border: none;
+ border-radius: 8px;
+ padding: 6px 4px;
+ min-width: 0;
+ box-shadow: none;
+ transition: background-color 120ms ease;
}
+.theme-card:hover,
+.theme-card:checked:hover {
+ background-color: alpha(@fg_text, 0.07);
+}
+.theme-card:checked {
+ background-color: alpha(@fg_text, 0.04);
+}
+.theme-card-name {
+ color: @fg_subtext;
+ font-size: 12px;
+ font-weight: 500;
+}
+.theme-card:checked .theme-card-name {
+ color: @fg_text;
+ font-weight: 600;
+}
+
+/* ------------------------------------------------------------------ */
+/* Statistics */
+/* ------------------------------------------------------------------ */
+
.stats-page {
padding: 8px 28px 24px 28px;
}
.stats-summary {
- margin-top: 8px;
- margin-bottom: 18px;
+ margin-top: 10px;
+ margin-bottom: 16px;
}
.stats-metric {
- background-color: alpha(@bg_surface0, 0.92);
- border: 1px solid @bg_surface1;
- border-radius: 16px;
- padding: 16px 18px;
+ padding: 14px 16px;
min-width: 120px;
}
.stats-metric-value {
color: @fg_text;
- font-size: 26px;
- font-weight: 800;
- letter-spacing: -0.4px;
+ font-size: 24px;
+ font-weight: 700;
+ letter-spacing: -0.5px;
}
.stats-metric-label {
- color: @fg_overlay;
- font-size: 11px;
- font-weight: 700;
- letter-spacing: 0.8px;
- margin-top: 4px;
-}
-.stats-overall-bar,
-.stats-overall-bar trough,
-.stats-unit-bar,
-.stats-unit-bar trough {
- min-height: 10px;
- min-width: 1px;
- border-radius: 6px;
- background-color: alpha(@bg_surface1, 0.85);
- border: none;
- padding: 0;
-}
-.stats-overall-bar {
- margin-bottom: 22px;
- min-height: 12px;
-}
-.stats-overall-bar progress,
-.stats-unit-bar progress {
- min-width: 1px;
- min-height: 10px;
- border-radius: 6px;
- background-image: linear-gradient(90deg, @accent 0%, @accent2 100%);
- background-color: @accent;
- border: none;
-}
-.stats-unit-bar.done progress {
- background-image: linear-gradient(90deg, @success 0%, @success2 100%);
- background-color: @success;
+ margin-top: 2px;
}
.stats-section {
- color: @fg_overlay;
- font-size: 11px;
- font-weight: 700;
- letter-spacing: 0.8px;
- margin-bottom: 10px;
+ margin-bottom: 8px;
}
.stats-subject {
margin-bottom: 20px;
}
.stats-subject-name {
color: @fg_text;
- font-size: 16px;
- font-weight: 800;
+ font-size: 15px;
+ font-weight: 600;
}
.stats-subject-count {
color: @fg_subtext;
font-size: 13px;
- font-weight: 700;
+ font-weight: 500;
}
.stats-subject-count.locked {
color: @fg_overlay;
}
-.stats-subject-bar,
-.stats-subject-bar trough {
- min-height: 12px;
- min-width: 1px;
- border-radius: 6px;
- background-color: alpha(@bg_surface1, 0.85);
- border: none;
- padding: 0;
-}
-.stats-subject-bar {
- margin: 4px 0 0 0;
-}
-.stats-subject-bar progress {
- min-width: 1px;
- min-height: 10px;
- border-radius: 6px;
- background-image: linear-gradient(90deg, @accent 0%, @accent2 100%);
- background-color: @accent;
- border: none;
-}
.stats-units {
margin-top: 8px;
- border-left: 2px solid alpha(@fg_overlay, 0.22);
- padding-left: 12px;
+ padding-left: 14px;
}
.stats-unit-row {
- background-color: alpha(@bg_surface0, 0.72);
- border: 1px solid @bg_surface1;
- border-radius: 14px;
- padding: 12px 14px;
- margin-bottom: 8px;
+ padding: 13px 14px;
+ margin-bottom: 6px;
}
.stats-unit-row.locked {
- opacity: 0.55;
+ opacity: 0.5;
}
.stats-unit-row.done {
- border-color: alpha(@success, 0.55);
+ border-color: alpha(@success, 0.5);
}
.stats-unit-index {
color: @fg_overlay;
font-size: 13px;
- font-weight: 700;
- min-width: 22px;
+ font-weight: 500;
+ min-width: 20px;
}
.stats-unit-name {
color: @fg_text;
font-size: 15px;
- font-weight: 700;
+ font-weight: 500;
}
.stats-unit-count {
color: @fg_subtext;
font-size: 13px;
- font-weight: 600;
+ font-weight: 500;
}
.stats-unit-badge {
color: @success;
font-size: 12px;
- font-weight: 700;
+ font-weight: 600;
}
-tooltip {
- background-color: @bg_mantle;
- border: 1px solid @bg_surface1;
- border-radius: 10px;
- color: @fg_text;
+
+/* One shared bar geometry; only the fill colour differs. */
+.stats-overall-bar,
+.stats-overall-bar trough,
+.stats-subject-bar,
+.stats-subject-bar trough,
+.stats-unit-bar,
+.stats-unit-bar trough {
+ min-height: 6px;
+ min-width: 6px;
+ border: none;
+ border-radius: 3px;
+ padding: 0;
+ background-color: alpha(@fg_text, 0.11);
+}
+.stats-overall-bar progress,
+.stats-subject-bar progress,
+.stats-unit-bar progress {
+ min-height: 6px;
+ min-width: 6px;
+ border: none;
+ border-radius: 3px;
+ background-image: none;
+ background-color: @accent;
+}
+.stats-unit-bar.done progress {
+ background-color: @success;
+}
+/* stats_set_fraction() marks bars at zero, whose fill GTK would otherwise
+ * still paint at its minimum width. */
+.stats-overall-bar.empty progress,
+.stats-subject-bar.empty progress,
+.stats-unit-bar.empty progress {
+ background-color: transparent;
+}
+.stats-overall-bar {
+ margin-bottom: 20px;
+}
+.stats-subject-bar {
+ margin-top: 6px;
}
/* no-scale */
/* Rules below keep a fixed size (symbols/icons) even when the window grows. */
.bubble-number.branch-star {
- font-size: 22px;
+ font-size: 20px;
}
diff --git a/subjects.c b/subjects.c
index 7c6cecb..69a0037 100644
--- a/subjects.c
+++ b/subjects.c
@@ -125,8 +125,6 @@ void draw_sub_rail(GtkDrawingArea *area, cairo_t *cr,
int width, int height, gpointer user_data) {
const double t_end = (double)(NUM_SUBJECTS - 1);
const Rgb rail = color_from_hex(app_theme.rail);
- const Rgb mauve = color_from_hex(app_theme.accent);
- double hx, hy;
(void)area;
(void)width;
@@ -139,13 +137,9 @@ void draw_sub_rail(GtkDrawingArea *area, cairo_t *cr,
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
- sub_point(0.0, &hx, &hy);
- draw_node_halo(cr, hx, hy, SUB_BUBBLE * 1.05,
- mauve.r, mauve.g, mauve.b, 0.18);
-
cairo_new_path(cr);
sub_path(cr, 0.0, t_end);
- cairo_set_line_width(cr, 14);
+ cairo_set_line_width(cr, 12);
cairo_set_source_rgb(cr, rail.r, rail.g, rail.b);
cairo_stroke(cr);
}