From 260b1151096381b3df230ef25a95d03be9c85bea Mon Sep 17 00:00:00 2001 From: Mae Beale Date: Wed, 12 Aug 2026 09:15:51 -0400 Subject: [PATCH 1/2] Add automated Tailwind class ordering and sub-xs text tokens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adopt two Tailwind chaos-prevention practices: automated class ordering (via rustywind, since Prettier's Tailwind plugin can't parse ERB) and semantic design tokens for the tiny font sizes that were scattered as arbitrary text-[…] values. Consolidating them keeps the dense-UI type consistent and adjustable in one place. Co-Authored-By: Claude Opus 4.8 (1M context) --- AGENTS.md | 5 +- CLAUDE.md | 1 + ai/README.md | 1 + ai/tw-sort | 52 +++++ .../stylesheets/application.tailwind.css | 7 + app/helpers/organization_helper.rb | 2 +- .../admin/ahoy_activities/charts.html.erb | 216 +++++++++--------- app/views/admin/analytics/index.html.erb | 63 +++-- .../allocations/_allocatable_link.html.erb | 2 +- app/views/allocations/_allocated_to.html.erb | 4 +- .../comments/_aggregated_comment.html.erb | 2 +- .../_payment_history.html.erb | 8 +- .../edit.html.erb | 14 +- .../_attendance_status_badge.html.erb | 4 +- .../_continuing_education.html.erb | 6 +- app/views/event_registrations/_form.html.erb | 22 +- .../_org_affiliation_pills.html.erb | 2 +- .../_payment_history.html.erb | 2 +- .../_readiness_badge.html.erb | 2 +- .../event_registrations/_scholarship.html.erb | 6 +- .../link_organization.html.erb | 2 +- .../events/_attendance_day_form.html.erb | 2 +- .../events/_attendance_sessions.html.erb | 2 +- .../events/_attendance_stat_row.html.erb | 6 +- app/views/events/_breakdown_card.html.erb | 6 +- .../events/_dashboard_money_row.html.erb | 8 +- app/views/events/_headcount_header.html.erb | 2 +- app/views/events/_organization_row.html.erb | 12 +- app/views/events/_participation_kpi.html.erb | 6 +- app/views/events/_recipient_card.html.erb | 12 +- .../events/_registrants_results.html.erb | 76 +++--- ...egistration_ticket_callout_fields.html.erb | 18 +- .../events/_revenue_breakdown_row.html.erb | 14 +- app/views/events/_revenue_kpi.html.erb | 6 +- .../_scholarship_recipient_group.html.erb | 2 +- .../_scholarship_recipients_cell.html.erb | 6 +- app/views/events/_stat_link.html.erb | 2 +- app/views/events/_stat_segment.html.erb | 4 +- app/views/events/attendance.html.erb | 18 +- .../ticket.html.erb | 64 +++--- .../events/callouts/_admin_edit_link.html.erb | 2 +- .../callouts/_ce_attendance_sheet.html.erb | 10 +- app/views/events/callouts/ce.html.erb | 38 +-- app/views/events/dashboard.html.erb | 8 +- app/views/events/onboarding/_results.html.erb | 14 +- app/views/events/onboarding/_row.html.erb | 4 +- app/views/events/roster.html.erb | 2 +- .../notifications/_communications.html.erb | 6 +- app/views/notifications/_index.html.erb | 18 +- .../_duplicate_organizations_warning.html.erb | 14 +- .../organizations/check_duplicates.html.erb | 22 +- .../people/_duplicate_people_warning.html.erb | 24 +- app/views/people/_form.html.erb | 127 +++++----- app/views/people/check_duplicates.html.erb | 38 +-- .../_professional_license_fields.html.erb | 20 +- app/views/resources/_resource_card.html.erb | 25 +- app/views/scholarships/_form.html.erb | 14 +- .../scholarships/_form_submission.html.erb | 6 +- app/views/scholarships/edit.html.erb | 2 +- app/views/shared/_badge.html.erb | 2 +- app/views/stories/_form.html.erb | 6 +- app/views/story_ideas/_form.html.erb | 18 +- .../topic_subscription_types/index.html.erb | 2 +- app/views/topic_subscriptions/_form.html.erb | 10 +- .../users/_duplicate_users_warning.html.erb | 14 +- app/views/users/_form.html.erb | 52 ++--- app/views/users/check_duplicates.html.erb | 34 +-- package-lock.json | 137 +++++++++++ package.json | 5 + 69 files changed, 779 insertions(+), 584 deletions(-) create mode 100755 ai/tw-sort diff --git a/AGENTS.md b/AGENTS.md index cf151739df..2818984914 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -399,9 +399,12 @@ end ### Tailwind Theme -Custom colors defined in `app/frontend/stylesheets/application.tailwind.css`: +Custom tokens defined in the `@theme` block of `app/frontend/stylesheets/application.tailwind.css`: - `--color-primary: #063b8d` (dark blue) - Standard semantic colors: secondary, danger, warning, info, success +- Sub-`xs` font sizes for dense UI: `text-2xs` (0.625rem) and `text-3xs` (0.55rem) — use these instead of arbitrary `text-[…px]` values + +Tailwind class order is sorted with rustywind via `ai/tw-sort` (Prettier's Tailwind plugin can't parse ERB). Prefer named theme tokens and static class literals over arbitrary/interpolated classes. ## Testing diff --git a/CLAUDE.md b/CLAUDE.md index 15dd1da027..9e35758599 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -384,6 +384,7 @@ See `ai/` directory for executable scripts: | `ai/test_extra [args]` | Full RSpec run: Vite test build + all system specs | | `ai/lint` | Rubocop on all files | | `ai/lint --fix` | Auto-fix lint issues | +| `ai/tw-sort` | Sort Tailwind class order (rustywind) on files changed vs main; `--all` for the whole tree, `--check` to verify without writing | | `ai/server` | Start dev services (web + vite) | | `ai/console` | Rails console | | `ai/routes -g pattern` | Search Rails routes | diff --git a/ai/README.md b/ai/README.md index 8b704d2059..560f0018dc 100644 --- a/ai/README.md +++ b/ai/README.md @@ -10,6 +10,7 @@ Quick-reference scripts for common development tasks. Designed for AI agents and | `ai/test_extra [args]` | Full RSpec run: Vite test build + all the headless-Chrome system specs `ai/test` narrows | | `ai/lint` | Rubocop on all files | | `ai/lint --fix` | Auto-fix lint issues | +| `ai/tw-sort` | Sort Tailwind utility-class order with rustywind. Defaults to files changed vs `origin/main` (gradual convergence); `--all` sorts the whole tree, `--check` verifies without writing (non-zero exit if any file is unsorted) | | `ai/server` | Start all dev services (web + vite) | | `ai/console` | Rails console | | `ai/routes -g pattern` | Search Rails routes | diff --git a/ai/tw-sort b/ai/tw-sort new file mode 100755 index 0000000000..411c78102f --- /dev/null +++ b/ai/tw-sort @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +# Sort Tailwind utility classes into canonical order with rustywind. +# +# ERB is where nearly all our classes live, and Prettier (with +# prettier-plugin-tailwindcss) can't parse ERB — so we use rustywind, which +# reorders only the class-attribute tokens in place and leaves interpolations +# (<%= ... %>) and the rest of the markup untouched. +# +# Usage: +# ai/tw-sort Sort files changed vs origin/main (gradual convergence) +# ai/tw-sort --check Check those files; non-zero exit if any need sorting +# ai/tw-sort --all Sort the whole tree (app/views + app/frontend/javascript) +# ai/tw-sort --all --check +set -euo pipefail +source "$(dirname "$0")/.ruby-env" + +rustywind="$(dirname "$0")/../node_modules/.bin/rustywind" + +mode="write" +scope="changed" +for arg in "$@"; do + case "$arg" in + --check) mode="check" ;; + --all) scope="all" ;; + *) echo "unknown option: $arg" >&2; exit 2 ;; + esac +done + +flag="--write" +[[ "$mode" == "check" ]] && flag="--check-formatted" + +if [[ "$scope" == "all" ]]; then + exec "$rustywind" "$flag" app/views app/frontend/javascript +fi + +# Changed files only: everything modified vs origin/main plus the working tree. +files=() +while IFS= read -r f; do + [[ -n "$f" && -f "$f" ]] && files+=("$f") +done < <( + { git diff --name-only --diff-filter=ACMR origin/main...HEAD + git diff --name-only --diff-filter=ACMR + git diff --name-only --diff-filter=ACMR --cached + } | sort -u | grep -E '\.(erb|js)$' || true +) + +if [[ ${#files[@]} -eq 0 ]]; then + echo "No changed .erb/.js files to sort." + exit 0 +fi + +exec "$rustywind" "$flag" "${files[@]}" diff --git a/app/frontend/stylesheets/application.tailwind.css b/app/frontend/stylesheets/application.tailwind.css index a40cce757d..4e8f93410f 100644 --- a/app/frontend/stylesheets/application.tailwind.css +++ b/app/frontend/stylesheets/application.tailwind.css @@ -17,6 +17,13 @@ --color-success: var(--color-green-500); --color-transparent: transparent; --font-telefon: "Telefon Bold", sans-serif; + + /* Sub-`text-xs` sizes for dense UI (badges, pills, stat rows). Named tokens + replacing scattered arbitrary font-size values so the tiny type stays + consistent and is adjustable in one place. 2xs (0.625rem/10px) consolidates + the ~10px cluster; 3xs (0.55rem) was the next size down. */ + --text-2xs: 0.625rem; + --text-3xs: 0.55rem; } /* Font face declarations */ diff --git a/app/helpers/organization_helper.rb b/app/helpers/organization_helper.rb index 659ff0f11d..20769ee632 100644 --- a/app/helpers/organization_helper.rb +++ b/app/helpers/organization_helper.rb @@ -56,7 +56,7 @@ def organization_profile_button(organization, truncate_at: nil, subtitle: nil, l label_tag = if label.present? content_tag(:span, label, - class: "absolute top-1 right-1 px-1.5 py-0.5 rounded text-[10px] font-semibold bg-gray-200 text-gray-600") + class: "absolute top-1 right-1 px-1.5 py-0.5 rounded text-2xs font-semibold bg-gray-200 text-gray-600") else "".html_safe end diff --git a/app/views/admin/ahoy_activities/charts.html.erb b/app/views/admin/ahoy_activities/charts.html.erb index ad9ba9eaf8..059a204126 100644 --- a/app/views/admin/ahoy_activities/charts.html.erb +++ b/app/views/admin/ahoy_activities/charts.html.erb @@ -1,6 +1,6 @@ <% content_for(:page_bg_class, "admin-only bg-blue-100") %> -
-
+
+
<% if allowed_to?(:index?, with: Admin::HomePolicy) %> <%= link_to admin_path, class: "inline-flex items-center gap-1 text-sm text-gray-500 hover:text-gray-700" do %> @@ -12,15 +12,15 @@
-
-

Charts

+
+

Charts

-
+
<%= render "admin/shared/active_filters_subheader" %>
-

Filters

+

Filters

<%= form_with url: admin_activities_charts_path, method: :get, local: true, class: "flex items-center gap-4" do %> <%= render "admin/shared/audience_dropdown" %> @@ -46,7 +46,7 @@
-
+
<% has_users = @audience_labels.include?("users") has_staff = @audience_labels.include?("staff") audience_note = if has_users && has_staff @@ -63,55 +63,55 @@ else "non-admin accounts" end %> -

+

Portal usage <% if audience_note %> - (<%= audience_note %>) + (<%= audience_note %>) <% end %>

-
+
<%= link_to users_path, class: "group relative bg-white border border-gray-200 rounded-xl shadow-sm p-6 hover:bg-blue-50 hover:border-blue-300 hover:shadow-md transition-all" do %> - -

Total users

+ +

Total users

-
<%= number_with_delimiter(@filtered_user_count) %>
+
<%= number_with_delimiter(@filtered_user_count) %>
<% if @audience_labels.include?("users") && @audience_labels.include?("staff") %> -
All user accounts in the system
-
<%= number_with_delimiter(@non_staff_users) %> non-admin · <%= number_with_delimiter(@staff_users) %> admin
+
All user accounts in the system
+
<%= number_with_delimiter(@non_staff_users) %> non-admin · <%= number_with_delimiter(@staff_users) %> admin
<% elsif @audience_labels.include?("staff") %> -
Admin accounts
-
of <%= number_with_delimiter(@total_users) %> total
+
Admin accounts
+
of <%= number_with_delimiter(@total_users) %> total
<% else %> -
Non-admin accounts
-
of <%= number_with_delimiter(@total_users) %> total
+
Non-admin accounts
+
of <%= number_with_delimiter(@total_users) %> total
<% end %>
<% end %> <%= link_to users_path(invited: "true"), class: "group relative bg-white border border-gray-200 rounded-xl shadow-sm p-6 hover:bg-blue-50 hover:border-blue-300 hover:shadow-md transition-all" do %> - -

Invited users

+ +

Invited users

-
<%= number_with_delimiter(@portal_access_users) %>
-
Sent the welcome instructions email
+
<%= number_with_delimiter(@portal_access_users) %>
+
Sent the welcome instructions email
<% if @has_access_users != @portal_access_users %> -
<%= @has_access_users %> have access of <%= number_with_delimiter(@filtered_user_count) %> <%= audience_count_label %>
+
<%= @has_access_users %> have access of <%= number_with_delimiter(@filtered_user_count) %> <%= audience_count_label %>
<% else %> -
of <%= number_with_delimiter(@filtered_user_count) %> <%= audience_count_label %>
+
of <%= number_with_delimiter(@filtered_user_count) %> <%= audience_count_label %>
<% end %>
<% end %> <%= link_to users_path(authenticated: "true"), class: "group relative bg-white border border-gray-200 rounded-xl shadow-sm p-6 hover:bg-blue-50 hover:border-blue-300 hover:shadow-md transition-all" do %> - -

Authenticated users

+ +

Authenticated users

-
<%= number_with_delimiter(@authenticated_users) %>
-
Logged in at least once
+
<%= number_with_delimiter(@authenticated_users) %>
+
Logged in at least once
<% if @confirmed_users != @authenticated_users %> -
<%= @confirmed_users %> confirmed of <%= number_with_delimiter(@filtered_user_count) %> <%= audience_count_label %>
+
<%= @confirmed_users %> confirmed of <%= number_with_delimiter(@filtered_user_count) %> <%= audience_count_label %>
<% else %> -
of <%= number_with_delimiter(@filtered_user_count) %> <%= audience_count_label %>
+
of <%= number_with_delimiter(@filtered_user_count) %> <%= audience_count_label %>
<% end %>
<% end %> @@ -131,40 +131,40 @@
-
-

Engagement patterns

-
+
+

Engagement patterns

+
<%= link_to admin_activities_visits_path, class: "group relative bg-white border border-gray-200 rounded-xl shadow-sm p-6 hover:bg-blue-50 hover:border-blue-300 hover:shadow-md transition-all" do %> - -

Total visits

+ +

Total visits

-
<%= number_with_delimiter(scoped_visits.count) %>
-
Sessions in selected period
+
<%= number_with_delimiter(scoped_visits.count) %>
+
Sessions in selected period
<% if @authenticated_visits > 0 && @public_visits > 0 %> -
<%= number_with_delimiter(@authenticated_visits) %> authenticated · <%= number_with_delimiter(@public_visits) %> public
+
<%= number_with_delimiter(@authenticated_visits) %> authenticated · <%= number_with_delimiter(@public_visits) %> public
<% end %>
<% end %> <%= link_to admin_activities_events_path, class: "group relative bg-white border border-gray-200 rounded-xl shadow-sm p-6 hover:bg-blue-50 hover:border-blue-300 hover:shadow-md transition-all" do %> - -

Total activities

+ +

Total activities

-
<%= number_with_delimiter(scoped_events.count) %>
-
Actions in selected period
+
<%= number_with_delimiter(scoped_events.count) %>
+
Actions in selected period
<% if @authenticated_visits > 0 && @public_visits > 0 %> -
<%= number_with_delimiter(@authenticated_visits) %> authenticated · <%= number_with_delimiter(@public_visits) %> public
+
<%= number_with_delimiter(@authenticated_visits) %> authenticated · <%= number_with_delimiter(@public_visits) %> public
<% end %>
<% end %> -
-

Avg activities per visit

+
+

Avg activities per visit

<%= @avg_events_per_visit %>
-
Actions per session
+
Actions per session
<% if @authenticated_visits > 0 && @public_visits > 0 %> -
<%= number_with_delimiter(@authenticated_visits) %> authenticated · <%= number_with_delimiter(@public_visits) %> public
+
<%= number_with_delimiter(@authenticated_visits) %> authenticated · <%= number_with_delimiter(@public_visits) %> public
<% end %>
@@ -192,19 +192,19 @@ <% end %>
-
-

Avg session duration

+
+

Avg session duration

<%= @avg_session_minutes %>
-
Minutes per session
+
Minutes per session
-
-

Public activities

+
+

Public activities

<%= @public_events_pct %>%
-
Activities from public visitors
-
<%= @public_visits_pct %>% of visits are public
+
Activities from public visitors
+
<%= @public_visits_pct %>% of visits are public
@@ -230,7 +230,7 @@ <% max_val = @heatmap_data.values.max.to_i %> <% max_val = 1 if max_val == 0 %>
- +
<% 7.times do %><% end %> @@ -239,18 +239,18 @@ <% days.each do |d| %> - + <% end %> <% (0..23).each do |hour| %> - + <% (1..7).each do |dow| %> <% val = @heatmap_data[[hour, dow]] || 0 %> <% opacity = (val.to_f / max_val).round(2) %> - - diff --git a/app/views/events/_dashboard_money_row.html.erb b/app/views/events/_dashboard_money_row.html.erb index c3d9e20c83..1979b93d12 100644 --- a/app/views/events/_dashboard_money_row.html.erb +++ b/app/views/events/_dashboard_money_row.html.erb @@ -27,7 +27,7 @@ <% if icon_bg.present? %> - + <% else %> @@ -37,7 +37,7 @@ <%= dollars_from_cents(amount_cents) %> - + <% if registrants.any? %> @@ -53,7 +53,7 @@ <% if person_cents %> <%= dollars_from_cents(person_cents) %> <% end %> - + <% end %> @@ -64,6 +64,6 @@ <% end %> <%= link_to filter_path, class: "shrink-0 flex h-7 items-center text-gray-300 hover:text-gray-500", title: "View #{label.downcase} registrants" do %> - + <% end %> diff --git a/app/views/events/_headcount_header.html.erb b/app/views/events/_headcount_header.html.erb index cca8575dc6..936d1d4ffc 100644 --- a/app/views/events/_headcount_header.html.erb +++ b/app/views/events/_headcount_header.html.erb @@ -20,7 +20,7 @@ (claims no space) until hover, so the label keeps its full width and only truncates to make room for the icon on hover. %> <% end %> diff --git a/app/views/events/_organization_row.html.erb b/app/views/events/_organization_row.html.erb index 6fcb5abfc1..ac228a90e5 100644 --- a/app/views/events/_organization_row.html.erb +++ b/app/views/events/_organization_row.html.erb @@ -5,17 +5,17 @@ arrow sits after the percentage, matching the other breakdown cards. %> <% is_scholarship = row[:scholarship_count].positive? %> <% path = row[:path] %> - transition-colors" + transition-colors" <% if path.present? %>onclick="window.location='<%= path %>'"<% end %>> - - diff --git a/app/views/events/_participation_kpi.html.erb b/app/views/events/_participation_kpi.html.erb index 78521f120b..be37d8bad5 100644 --- a/app/views/events/_participation_kpi.html.erb +++ b/app/views/events/_participation_kpi.html.erb @@ -5,12 +5,12 @@ <%= content_tag tag, href: href, class: class_names("block rounded-xl border p-4", card_class, "relative transition-shadow hover:shadow-md" => href.present?) do %> <% if href %> - + <% end %> -
href.present?) %>"><%= label %>
+
href.present?) %>"><%= label %>
<%= number_with_delimiter(value) %>
<% if note %> -
(<%= note %>)
+
(<%= note %>)
<% end %> <% delta = participation_delta(value, local_assigns[:prior]) %> <% if delta %> diff --git a/app/views/events/_recipient_card.html.erb b/app/views/events/_recipient_card.html.erb index ae63dd75b1..06a8b66aa7 100644 --- a/app/views/events/_recipient_card.html.erb +++ b/app/views/events/_recipient_card.html.erb @@ -20,7 +20,7 @@ } %>
" - class="scroll-mt-24 bg-white border <%= DomainTheme.border_class_for(:scholarships) %> rounded-xl shadow-sm overflow-hidden break-inside-avoid" + class="scroll-mt-24 border bg-white <%= DomainTheme.border_class_for(:scholarships) %> break-inside-avoid overflow-hidden rounded-xl shadow-sm" data-controller="expandable-card" data-action="expandable-cards:expandAll@window->expandable-card#expand expandable-cards:collapseAll@window->expandable-card#collapse"> <%# Recipient header — avatar + name, with title/org beneath the name and the @@ -74,7 +74,7 @@ title: "View #{person.name}'s registration", class: "shrink-0 inline-flex items-center gap-1 text-sm text-gray-400 hover:text-gray-600" do %> - + <% end %> <% end %>
@@ -132,7 +132,7 @@
- Scholarship + Scholarship <%= dollars_from_cents(scholarship.amount_cents) %> @@ -143,7 +143,7 @@ class: "inline-flex items-center gap-1.5 text-sm text-gray-600 hover:text-gray-800 hover:underline" do %> Funded by <%= scholarship.grant.funder_name %> - + <% end %> <% else %> @@ -158,7 +158,7 @@ class: "ml-auto inline-flex items-center gap-1.5 text-xs font-medium text-gray-500 hover:text-gray-700 hover:underline", target: "_blank", rel: "noopener" do %> Edit - + <% end %> <% end %>
@@ -172,7 +172,7 @@ <% answers.each do |answer| %>
<%= display_question_label(answer.form_field, answer) %>
-
<%= resolve_answer_text(answer.form_field, answer.submitted_answer) %>
+
<%= resolve_answer_text(answer.form_field, answer.submitted_answer) %>
<% end %> diff --git a/app/views/events/_registrants_results.html.erb b/app/views/events/_registrants_results.html.erb index 0aadb4da90..04b508fba7 100644 --- a/app/views/events/_registrants_results.html.erb +++ b/app/views/events/_registrants_results.html.erb @@ -1,8 +1,8 @@ <%= turbo_frame_tag :registrants_results do %> <%# Scholarship column shows by default only when the event charges a fee. %> <% scholarship_on = @event.cost_cents.to_i > 0 %> -
-
+
+
<% current_filter = params[:attendance_status].present? ? nil : (params[:status_filter].presence || "active") %>
<% end %> - - - + + <% readiness = @readiness[registration.id] %> - - @@ -512,7 +512,7 @@
<%= d %><%= d %>
<%= "#{hour}:00" %><%= "#{hour}:00" %> @@ -269,9 +269,9 @@
-
-

Workshop analytics

-
+
+

Workshop analytics

+
<%= chart_card("Workshop search: category types") { bar_chart(@ws_category_types) } %> <%= chart_card("Workshop search: categories") { bar_chart(@ws_category_names) } %> <%= chart_card("Workshop search: sectors") { bar_chart(@ws_sectors) } %> @@ -286,9 +286,9 @@
-
-

Resource analytics

-
+
+

Resource analytics

+
<%= chart_card("Resource search: keywords") { bar_chart(@rs_keywords) } %> <%= chart_card("Resource search: kinds") { bar_chart(@rs_kinds) } %> <%= chart_card("Resource discovery funnel") { column_chart(@rs_funnel) } %> @@ -297,27 +297,27 @@
-
-

Tag analytics

-
+
+

Tag analytics

+
<%= link_to tags_path, class: "group relative bg-white border border-gray-200 rounded-xl shadow-sm p-6 hover:bg-blue-50 hover:border-blue-300 hover:shadow-md transition-all" do %> - -

Tags page views

+ +

Tags page views

-
<%= number_with_delimiter(@tags_page_views) %>
+
<%= number_with_delimiter(@tags_page_views) %>
<% end %> <%= link_to taggings_path, class: "group relative bg-white border border-gray-200 rounded-xl shadow-sm p-6 hover:bg-blue-50 hover:border-blue-300 hover:shadow-md transition-all" do %> - -

Taggings page views

+ +

Taggings page views

-
<%= number_with_delimiter(@taggings_page_views) %>
+
<%= number_with_delimiter(@taggings_page_views) %>
<% end %> -
-

Tagging searches

+
+

Tagging searches

<%= number_with_delimiter(@tagging_searches) %>
@@ -329,13 +329,13 @@ <%= chart_card("Tagging search origin") { pie_chart(@tagging_search_origin) } %> -
-

Top filter combinations

+
+

Top filter combinations

    <% @top_filter_combos.each do |label, count| %> -
  • - <%= count %> - × +
  • + <%= count %> + × <%= label %>
  • <% end %> @@ -346,9 +346,9 @@
-
-

Content discovery

-
+
+

Content discovery

+
<%= chart_card("Content types people view most") do %> <%= pie_chart( scoped_events @@ -376,33 +376,33 @@
-
-

Content creation

-
-
-

Ideas submitted

+
+

Content creation

+
+
+

Ideas submitted

<%= number_with_delimiter(@ideas_submitted) %>
-
-

Ideas promoted

+
+

Ideas promoted

<%= number_with_delimiter(@ideas_promoted) %>
-
Converted to published content
+
Converted to published content
-
-

Avg ideas per person

+
+

Avg ideas per person

<%= @avg_ideas_per_person %>
-
-

Total content created

+
+

Total content created

    <% @total_generated_content.each do |row| %> <% if row == [ :spacer ] %> @@ -411,7 +411,7 @@ <% label, total, idea_count, admin_count, promoted = row %>
  • <%= total %> - × + × <%= label %> <% if idea_count.present? && admin_count.present? %> <% p = promoted || 0 %> @@ -426,24 +426,24 @@
-
-

User-generated content

+
+

User-generated content

    <% @user_generated_content.each do |label, count, promoted| %>
  • <%= count %> - × + × <%= label %> <% if promoted.present? && promoted > 0 %> - (<%= promoted %> promoted) + (<%= promoted %> promoted) <% end %>
  • <% end %>
-
-

Admin-generated content

+
+

Admin-generated content

    <% @admin_generated_content.each do |row| %> <% if row == [ :spacer ] %> @@ -452,10 +452,10 @@ <% label, count, promoted = row %>
  • <%= count %> - × + × <%= label %> <% if promoted.present? && promoted > 0 %> - (incl <%= promoted %> promoted ideas) + (incl <%= promoted %> promoted ideas) <% end %>
  • <% end %> @@ -467,9 +467,9 @@
-
-

Referrals & technical

-
+
+

Referrals & technical

+
<%= chart_card("Top referrer → landing pages") do %> <%= bar_chart @top_referrer_landing, library: { indexAxis: "y" } %> <% end %> diff --git a/app/views/admin/analytics/index.html.erb b/app/views/admin/analytics/index.html.erb index fd3faa9e66..d44250f51e 100644 --- a/app/views/admin/analytics/index.html.erb +++ b/app/views/admin/analytics/index.html.erb @@ -1,6 +1,6 @@ <% content_for(:page_bg_class, "admin-only bg-blue-100") %> -
-
+
+
<% if allowed_to?(:index?, with: Admin::HomePolicy) %> <%= link_to admin_path, class: "inline-flex items-center gap-1 text-sm text-gray-500 hover:text-gray-700" do %> @@ -12,15 +12,15 @@
-
-

Counts

+
+

Counts

-
+
<%= render "admin/shared/active_filters_subheader" %>
-

Filters

+

Filters

<%= form_with url: admin_activities_counts_path, method: :get, local: true, class: "flex items-center gap-4" do |f| %> <%= render "admin/shared/audience_dropdown" %> @@ -44,22 +44,21 @@
-
-

+
+

View counts

-
+
<% @summary.each do |label, data| %> <%= link_to polymorphic_path(label.to_s.classify.constantize), class: "block group" do %> -
- -
+
+ +
<%= label.to_s.humanize %>
-
+
<%= number_with_delimiter(data[:views]) %>
@@ -79,9 +78,9 @@

-
-

Workshops

-
+
+

Workshops

+
<%= render "admin/analytics/popular_list", title: "Most viewed", records: @most_viewed_workshops, @@ -102,9 +101,9 @@
-
-

Resources

-
+
+

Resources

+
<%= render "admin/analytics/popular_list", title: "Most viewed", records: @most_viewed_resources, @@ -128,9 +127,9 @@
-
-

<%= CommunityNews.model_name.human.pluralize %>

-
+
+

<%= CommunityNews.model_name.human.pluralize %>

+
<%= render "admin/analytics/popular_list", title: "Most viewed", records: @most_viewed_community_news, @@ -151,9 +150,9 @@
-
-

Stories

-
+
+

Stories

+
<%= render "admin/analytics/popular_list", title: "Most viewed", records: @most_viewed_stories, @@ -174,9 +173,9 @@
-
-

Other

-
+
+

Other

+
<%= render "admin/analytics/popular_list", title: "Events", records: @most_viewed_events, @@ -230,12 +229,12 @@
-
-

+
+

No engagement

-
+
<%= render "zero_list", title: "Workshops", records: @zero_engagement_workshops, diff --git a/app/views/allocations/_allocatable_link.html.erb b/app/views/allocations/_allocatable_link.html.erb index d1778a06d2..4565a12303 100644 --- a/app/views/allocations/_allocatable_link.html.erb +++ b/app/views/allocations/_allocatable_link.html.erb @@ -14,7 +14,7 @@ <%= descriptor[:subtitle] %> <% end %> - + <% end %> <% else %> diff --git a/app/views/allocations/_allocated_to.html.erb b/app/views/allocations/_allocated_to.html.erb index 8b9034b026..48021a4f3b 100644 --- a/app/views/allocations/_allocated_to.html.erb +++ b/app/views/allocations/_allocated_to.html.erb @@ -2,12 +2,12 @@ allocatable is an event registration, the whole block is a button to its admin page with a jump-link icon in the top-right corner. ---%>
- Allocated to: + Allocated to: <% if allocatable.is_a?(EventRegistration) %> <%= link_to edit_event_registration_path(allocatable), class: "relative block rounded-lg border border-gray-300 bg-white px-3 py-2 pr-8 transition-colors hover:border-gray-400 hover:bg-gray-50", data: { turbo_frame: "_top" } do %> - + Event registration for <%= allocatable.registrant&.full_name %> <%= allocatable.event.title %> · <%= allocatable.event.decorate.times(display_day: true, display_date: true) %> <% end %> diff --git a/app/views/comments/_aggregated_comment.html.erb b/app/views/comments/_aggregated_comment.html.erb index 146b6b59bd..66f5cb7753 100644 --- a/app/views/comments/_aggregated_comment.html.erb +++ b/app/views/comments/_aggregated_comment.html.erb @@ -20,7 +20,7 @@ <%= render "comments/flag_toggle", commentable: comment.commentable, comment: comment.object %>
diff --git a/app/views/continuing_education_registrations/_payment_history.html.erb b/app/views/continuing_education_registrations/_payment_history.html.erb index b96408c4b0..738af1ae03 100644 --- a/app/views/continuing_education_registrations/_payment_history.html.erb +++ b/app/views/continuing_education_registrations/_payment_history.html.erb @@ -13,14 +13,14 @@ class: "ml-auto inline-flex items-center gap-1.5 text-xs font-medium text-gray-500 hover:text-gray-700 hover:underline", target: "_blank", rel: "noopener" do %> View all - + <% end %>
-
CE cost
+
CE cost
<% if params[:admin] == "true" %>
<%= number_field_tag "continuing_education_registration[cost_dollars]", @@ -35,14 +35,14 @@ <%= link_to allocations_path(allocatable_sgid: ce_registration.to_sgid.to_s, return_to: "ce_registration"), target: "_blank", rel: "noopener", class: "rounded-lg border border-gray-300 bg-gray-50 px-4 py-3 block transition hover:border-gray-400 hover:shadow-sm" do %> -
Amount allocated
+
Amount allocated
<%= dollars_from_cents(paid_cents) %>
<% end %> <% amount_due = due_cents > 0 %> <%= link_to allocations_path(allocatable_sgid: ce_registration.to_sgid.to_s, return_to: "ce_registration"), target: "_blank", rel: "noopener", class: "rounded-lg border px-4 py-3 block transition hover:shadow-sm #{amount_due ? "border-amber-300 bg-amber-50 hover:border-amber-400" : "border-gray-300 bg-gray-50 hover:border-gray-400"}" do %> -
Amount due
+
Amount due
"> <% if amount_due %> diff --git a/app/views/continuing_education_registrations/edit.html.erb b/app/views/continuing_education_registrations/edit.html.erb index 77b8ac40a9..ed89bc09ed 100644 --- a/app/views/continuing_education_registrations/edit.html.erb +++ b/app/views/continuing_education_registrations/edit.html.erb @@ -2,9 +2,9 @@ <% registration = @ce_registration.event_registration %> <% license = @ce_registration.professional_license %> -
+
<%# Top bar: back link + secondary links, matching the scholarship edit page %> -
+
<%= link_to ce_registration_return_path(registration), class: "text-sm text-gray-500 hover:text-gray-700" do %> <%= ce_registration_return_label %> <% end %> @@ -15,7 +15,7 @@ <%= render "shared/badge", label: "Registrant's CE page", classes: "bg-sky-100 text-sky-700 border-sky-200", - icon: "fa-solid fa-id-card text-[0.6rem]", + icon: "fa-solid fa-id-card text-2xs", href: registration_ce_path(registration.slug, return_to: "ce_registration"), target: "_blank", rel: "noopener" %> <%= link_to "Home", root_path, class: "text-sm text-gray-500 hover:text-gray-700" %> @@ -50,7 +50,7 @@ class: "ml-auto inline-flex items-center gap-1.5 text-xs font-medium text-transparent hover:text-gray-600 hover:underline", target: "_blank", rel: "noopener" do %> View all - + <% end %> <% end %>
@@ -69,14 +69,14 @@ partial: "comments/comment_fields", data: { association_insertion_node: "#comment-list", association_insertion_method: "append" }, class: "inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-xs font-medium text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-700 cursor-pointer" do %> - + Add comment <% end %> diff --git a/app/views/event_registrations/_attendance_status_badge.html.erb b/app/views/event_registrations/_attendance_status_badge.html.erb index 768ce79e32..126cfaa745 100644 --- a/app/views/event_registrations/_attendance_status_badge.html.erb +++ b/app/views/event_registrations/_attendance_status_badge.html.erb @@ -1,7 +1,7 @@ <% deco = registration.decorate %>
<%= form_with model: registration, url: event_registration_path(registration), method: :patch, data: { turbo_frame: "_top" } do |f| %> -
+
<%= f.select :status, EventRegistration::ATTENDANCE_STATUSES.map { |s| [EventRegistration.new(status: s).attendance_status_label, s] }, @@ -10,7 +10,7 @@ onchange: "this.form.requestSubmit()", "aria-label": "Change attendance status" %> <%= registration.attendance_status_label %> - +
<% end %>
diff --git a/app/views/event_registrations/_continuing_education.html.erb b/app/views/event_registrations/_continuing_education.html.erb index 04f3d56270..5c9cf62bea 100644 --- a/app/views/event_registrations/_continuing_education.html.erb +++ b/app/views/event_registrations/_continuing_education.html.erb @@ -17,9 +17,9 @@ <%= link_to new_continuing_education_registration_path(allocatable_sgid: event_registration.to_sgid.to_s, return_to: "registration"), class: "inline-flex items-center gap-1.5 self-start rounded-md px-2 py-1 text-xs font-medium text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-700", target: "_blank", rel: "noopener" do %> - + Add CE registration - + <% end %>
<% else %> @@ -33,7 +33,7 @@ class: "ml-auto inline-flex items-center gap-1.5 text-xs font-medium text-gray-500 hover:text-gray-700 hover:underline", target: "_blank", rel: "noopener" do %> Edit - + <% end %>
diff --git a/app/views/event_registrations/_form.html.erb b/app/views/event_registrations/_form.html.erb index f658ccb844..f5b965b516 100644 --- a/app/views/event_registrations/_form.html.erb +++ b/app/views/event_registrations/_form.html.erb @@ -63,7 +63,7 @@ end %> <% account_box = capture do %> - User account + User account <% end %> <% if allowed_to?(:show?, account) %> <%= link_to user_path(account), class: "#{box_base} #{account_border}", title: "User account: #{account_status}", data: { turbo_frame: "_top" } do %> @@ -75,12 +75,12 @@ <% elsif allowed_to?(:new?, User) %> <%= link_to new_user_path(person_id: f.object.registrant_id, event_registration_id: f.object.id), class: "#{box_base} border-gray-300 text-gray-600", title: "Create a user account", data: { turbo_frame: "_top" } do %> - Create user + Create user <% end %> <% else %>
- No account + No account
<% end %> @@ -88,9 +88,9 @@
Registration status
@@ -122,7 +122,7 @@ data: { turbo_frame: "_top" } do %> View ticket - + <% end %> <% end %> @@ -134,7 +134,7 @@ data: { turbo_frame: "_top" } do %> View form submission<%= " ##{i + 1}" if submissions.size > 1 %> - + <% end %> <% end %> @@ -210,7 +210,7 @@ data-org-toggle-target="addButton" data-action="org-toggle#showAddForm" class="inline-flex items-center gap-1.5 self-start rounded-md px-2 py-1 text-xs font-medium text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-700 cursor-pointer"> - + Connect organization
@@ -287,7 +287,7 @@ class: "ml-auto inline-flex items-center gap-1.5 text-xs font-medium text-transparent hover:text-gray-600 hover:underline", target: "_blank", rel: "noopener" do %> View all - + <% end %> <% end %>
@@ -306,7 +306,7 @@ partial: "comments/comment_fields", data: { association_insertion_node: "#comment-list", association_insertion_method: "append" }, class: "inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-xs font-medium text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-700 cursor-pointer" do %> - + Add comment <% end %> @@ -315,7 +315,7 @@ class="inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-xs font-medium text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-700 cursor-pointer" data-action="edit-toggle#toggle" > - + Edit comments diff --git a/app/views/event_registrations/_org_affiliation_pills.html.erb b/app/views/event_registrations/_org_affiliation_pills.html.erb index 991ebc581b..fd6c5d78ca 100644 --- a/app/views/event_registrations/_org_affiliation_pills.html.erb +++ b/app/views/event_registrations/_org_affiliation_pills.html.erb @@ -6,7 +6,7 @@ <% position = submitted_position.to_s.strip %> <% is_submitted_org = submitted_org_name.to_s.strip.present? && org.name.to_s.strip.casecmp?(submitted_org_name.to_s.strip) %>
- Affiliations: + Affiliations: <% affiliations.each do |a| %> <% a_active = active.call(a) %> <% color = a_active && !local_assigns[:neutral] ? "bg-green-50 text-green-700 border-green-200" : "bg-gray-100 text-gray-600 border-gray-200" %> diff --git a/app/views/event_registrations/_payment_history.html.erb b/app/views/event_registrations/_payment_history.html.erb index 13f5674696..b70a92646b 100644 --- a/app/views/event_registrations/_payment_history.html.erb +++ b/app/views/event_registrations/_payment_history.html.erb @@ -16,7 +16,7 @@ class: "ml-auto inline-flex items-center gap-1.5 text-xs font-medium text-gray-500 hover:text-gray-700 hover:underline after:absolute after:inset-0 after:content-['']", target: "_blank", rel: "noopener" do %> View all - + <% end %>
diff --git a/app/views/event_registrations/_readiness_badge.html.erb b/app/views/event_registrations/_readiness_badge.html.erb index 22f89d3224..f112001ad2 100644 --- a/app/views/event_registrations/_readiness_badge.html.erb +++ b/app/views/event_registrations/_readiness_badge.html.erb @@ -20,6 +20,6 @@
<%= render "shared/badge", label: label, classes: style, icon: "fas #{icon}", title: tooltip %> <% if subtext.present? %> - <%= subtext %> + <%= subtext %> <% end %>
diff --git a/app/views/event_registrations/_scholarship.html.erb b/app/views/event_registrations/_scholarship.html.erb index 88ce06e026..1e6a7fce30 100644 --- a/app/views/event_registrations/_scholarship.html.erb +++ b/app/views/event_registrations/_scholarship.html.erb @@ -31,7 +31,7 @@ class: "ml-auto inline-flex items-center gap-1.5 text-xs font-medium text-gray-500 hover:text-gray-700 hover:underline", target: "_blank", rel: "noopener" do %> Edit - + <% end %>
@@ -80,9 +80,9 @@ <%= link_to new_scholarship_path(allocatable_sgid: event_registration.to_sgid.to_s, return_to: "registration"), class: "inline-flex items-center gap-1.5 self-start rounded-md px-2 py-1 text-xs font-medium text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-700", target: "_blank", rel: "noopener" do %> - + Add scholarship - + <% end %>
<% end %> diff --git a/app/views/event_registrations/link_organization.html.erb b/app/views/event_registrations/link_organization.html.erb index baebbfd995..d396b5c79b 100644 --- a/app/views/event_registrations/link_organization.html.erb +++ b/app/views/event_registrations/link_organization.html.erb @@ -53,7 +53,7 @@ data: { turbo_frame: "_top" } do %>
-

Organization: <%= entry[:org_name].presence || "—" %><% if entry[:organization]&.city_state.present? %> · <%= entry[:organization].city_state %><% end %><%# Mirror the roster's amber "Pending" chip so it's clear why this registrant was flagged — shown only while nothing is linked. %><% if entry[:org_name].present? && @linked_organizations.none? %> <%= render "shared/badge", label: "Pending", classes: "bg-amber-50 text-amber-700 border-amber-200", icon: "fa-solid fa-circle-exclamation text-[0.65rem]", extra: "ml-1", title: "The registrant submitted this organization, but none is linked to the registration yet." %><% end %>

+

Organization: <%= entry[:org_name].presence || "—" %><% if entry[:organization]&.city_state.present? %> · <%= entry[:organization].city_state %><% end %><%# Mirror the roster's amber "Pending" chip so it's clear why this registrant was flagged — shown only while nothing is linked. %><% if entry[:org_name].present? && @linked_organizations.none? %> <%= render "shared/badge", label: "Pending", classes: "bg-amber-50 text-amber-700 border-amber-200", icon: "fa-solid fa-circle-exclamation text-2xs", extra: "ml-1", title: "The registrant submitted this organization, but none is linked to the registration yet." %><% end %>

Position / title: <%= entry[:position].presence || "—" %>

<% end %> diff --git a/app/views/events/_attendance_day_form.html.erb b/app/views/events/_attendance_day_form.html.erb index efe9b50394..09b760418e 100644 --- a/app/views/events/_attendance_day_form.html.erb +++ b/app/views/events/_attendance_day_form.html.erb @@ -36,6 +36,6 @@
<%= link_to "Cancel", cancel_path, class: "text-xs text-gray-500 hover:text-gray-700" %> - Leave the sign-out blank to leave a session open. + Leave the sign-out blank to leave a session open.
<% end %> diff --git a/app/views/events/_attendance_sessions.html.erb b/app/views/events/_attendance_sessions.html.erb index 217d912c19..6770520a81 100644 --- a/app/views/events/_attendance_sessions.html.erb +++ b/app/views/events/_attendance_sessions.html.erb @@ -32,7 +32,7 @@ <%= link_to attendance_event_path(@event, **state, edit: cell, anchor: cell), class: "ml-1 rounded px-1.5 py-0.5 text-xs font-medium text-teal-700 opacity-50 transition-opacity hover:bg-teal-50 hover:underline group-hover:opacity-100 focus:opacity-100", "aria-label": "Edit #{row.name}'s times for #{date.strftime("%b %-d")}" do %> - Edit + Edit <% end %>
<% end %> diff --git a/app/views/events/_attendance_stat_row.html.erb b/app/views/events/_attendance_stat_row.html.erb index bef26851e6..1d2d866da9 100644 --- a/app/views/events/_attendance_stat_row.html.erb +++ b/app/views/events/_attendance_stat_row.html.erb @@ -23,7 +23,7 @@ <%= count %> <%= label %> - + <% if registrants.any? %>
    @@ -33,7 +33,7 @@ title: [ registrant.name, *@dashboard.organization_names_by_registrant[registrant.id] ].join(" · "), class: "group/rowlink flex items-center justify-between gap-2 rounded px-1 -mx-1 py-0.5 hover:bg-gray-50" do %> <%= registrant.name %> - + <% end %> <% end %> @@ -43,6 +43,6 @@ <% end %> <%= link_to filter_path, class: "shrink-0 flex h-7 items-center text-gray-300 hover:text-gray-500", title: "View #{label.downcase} registrants" do %> - + <% end %>

diff --git a/app/views/events/_breakdown_card.html.erb b/app/views/events/_breakdown_card.html.erb index 9c1c538f1b..3fa581c30b 100644 --- a/app/views/events/_breakdown_card.html.erb +++ b/app/views/events/_breakdown_card.html.erb @@ -56,7 +56,7 @@ <% if path %>onclick="window.location='<%= path %>'"<% end %>>
<% if chart == :pie %> - + <% end %> <% if path %> <%= link_to label, path, class: "group-hover:underline" %> @@ -64,11 +64,11 @@ <%= label %> <% end %> + <%= count %> · <%= total.zero? ? 0 : (count * 100.0 / total).round(1) %>% <%# Jump-link affordance: invisible (white) until the row is hovered, matching the dashboard rows. %> <% if path %> - + <% end %>
- + + <% if is_scholarship %> " aria-hidden="true"> <% end %> <% if row[:high_profile] %> - + <% end %> <% if path.present? %> <%= link_to row[:name], path, class: "group-hover:underline align-middle" %> @@ -23,11 +23,11 @@ <%= row[:name] %> <% end %> + "><%= row[:count] %> · <%= total.zero? ? 0 : (row[:count] * 100.0 / total).round(1) %>% <%# Jump-link affordance: invisible (white) until the row is hovered, matching the other breakdown cards. %> <% if path.present? %> - + <% end %>
" data-column-toggle-col="scholarship" data-sort-value="<%= scholarship_sort %>"> + " data-column-toggle-col="scholarship" data-sort-value="<%= scholarship_sort %>"> <% if (s = scholarship) %> <% if s.tasks_completed? %> <%= render "shared/badge", @@ -429,7 +429,7 @@ <% if @event.cost_cents.to_i > 0 %> <% paid_cents = registration.allocations_sum %> <% due_cents = @event.cost_cents - paid_cents %> - + <% is_paid = registration.paid_in_full? %> <% is_discounted = !is_paid && registration.discounted? %> <% is_partial = !is_discounted && registration.partially_paid? %> @@ -460,7 +460,7 @@ title: badge_title %> <% if !is_paid && registration.intends_to_pay? %> -
+
Intends to pay
@@ -468,9 +468,9 @@ <% payment_badges = registration.decorate.payment_badges %> <% if payment_badges.any? %> -
<%= render "event_registrations/attendance_status_badge", registration: registration %><%= render "event_registrations/attendance_status_badge", registration: registration %> + <%= render "event_registrations/readiness_badge", status: readiness.status, label: readiness.status_label, issues: readiness.status_issues, subtext: readiness.status_reason %> <%= link_to "Edit", edit_event_registration_path(registration, return_to: "registrants"), class: "text-gray-500 hover:text-gray-700 underline", data: { turbo_frame: "_top" } %>
<% else %> -

No registrants found.

+

No registrants found.

<% end %>
<% end %> diff --git a/app/views/events/_registration_ticket_callout_fields.html.erb b/app/views/events/_registration_ticket_callout_fields.html.erb index 95b1d4dfe1..10a0278f0b 100644 --- a/app/views/events/_registration_ticket_callout_fields.html.erb +++ b/app/views/events/_registration_ticket_callout_fields.html.erb @@ -89,7 +89,7 @@ toggles `hidden`). Defaults open when published, closed otherwise; render the matching initial state to avoid a flash before the controller connects. `mt-5` keeps the preview card clear of the controls above it. %> -
space-y-3 mt-5 cursor-auto select-auto" data-expandable-card-target="body"> +
mt-5 cursor-auto space-y-3 select-auto" data-expandable-card-target="body"> <% if f.object.staff? %>
@@ -122,9 +122,9 @@ identity (title + presentation) on the left, its page content on the right. %> -
+
-
+
<%= f.label :title, "Title", class: "block text-xs font-medium text-gray-600 mb-0.5" %><%= f.text_field :title, required: true, class: "w-full rounded border-gray-300 bg-white shadow-sm px-2 py-1 text-sm" %>
@@ -154,7 +154,7 @@
- + Type, color, and icon @@ -202,7 +202,7 @@ <% unless f.object.payment? %>
> - + Visibility @@ -229,7 +229,7 @@ <%# RIGHT COLUMN: linked resources. Opened on load only when resources are saved. %>
> - + Linked resources @@ -240,13 +240,13 @@ <%# Column headers — mirror the row's flex + 3-col grid (plus a spacer for the remove button) so they line up. Hidden on mobile, where the fields stack to one column. %> -