@mathscan/math-exercise-engine 1.2.2 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +21869 -7530
- package/dist/index.js +1751 -60
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1751 -60
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +810 -4
- package/package.json +1 -1
package/dist/style.css
CHANGED
|
@@ -794,8 +794,14 @@ button.drag-option {
|
|
|
794
794
|
color: var(--exercise-text);
|
|
795
795
|
}
|
|
796
796
|
|
|
797
|
+
/*
|
|
798
|
+
* --exercise-table-border-color is always set inline by LayoutRenderer, which
|
|
799
|
+
* falls back to DEFAULT_TABLE_BORDER_COLOR. No literal default here: the color
|
|
800
|
+
* has one source of truth in src/constants/table-constants.ts.
|
|
801
|
+
*/
|
|
802
|
+
|
|
797
803
|
.exercise-table-container {
|
|
798
|
-
border: 2px solid
|
|
804
|
+
border: 2px solid var(--exercise-table-border-color);
|
|
799
805
|
border-radius: 8px;
|
|
800
806
|
overflow: hidden;
|
|
801
807
|
}
|
|
@@ -807,19 +813,19 @@ table.exercise-table {
|
|
|
807
813
|
|
|
808
814
|
td.exercise-table-cell,
|
|
809
815
|
th.exercise-table-cell {
|
|
810
|
-
box-shadow: inset -2px -2px 0 0
|
|
816
|
+
box-shadow: inset -2px -2px 0 0 var(--exercise-table-border-color);
|
|
811
817
|
}
|
|
812
818
|
|
|
813
819
|
td.exercise-table-cell:last-child,
|
|
814
820
|
th.exercise-table-cell:last-child {
|
|
815
|
-
box-shadow: inset 0 -2px 0 0
|
|
821
|
+
box-shadow: inset 0 -2px 0 0 var(--exercise-table-border-color);
|
|
816
822
|
}
|
|
817
823
|
|
|
818
824
|
tr.exercise-table-row:last-child td.exercise-table-cell,
|
|
819
825
|
tr.exercise-table-row:last-child th.exercise-table-cell,
|
|
820
826
|
td.exercise-table-cell.exercise-table-cell--last-row,
|
|
821
827
|
th.exercise-table-cell.exercise-table-cell--last-row {
|
|
822
|
-
box-shadow: inset -2px 0 0 0
|
|
828
|
+
box-shadow: inset -2px 0 0 0 var(--exercise-table-border-color);
|
|
823
829
|
}
|
|
824
830
|
|
|
825
831
|
tr.exercise-table-row:last-child td.exercise-table-cell:last-child,
|
|
@@ -2630,6 +2636,806 @@ th.exercise-table-cell.exercise-table-cell--last-row:last-child {
|
|
|
2630
2636
|
transform: none;
|
|
2631
2637
|
}
|
|
2632
2638
|
|
|
2639
|
+
/**
|
|
2640
|
+
* Chart widget styles
|
|
2641
|
+
*
|
|
2642
|
+
* All colours and sizes are driven by CSS custom properties defined inside
|
|
2643
|
+
* `.math-exercise-renderer` (variables.css). Consumer apps can override any
|
|
2644
|
+
* of these variables on a parent selector to theme the chart without touching
|
|
2645
|
+
* engine code.
|
|
2646
|
+
*
|
|
2647
|
+
* Override surface example (student app):
|
|
2648
|
+
*
|
|
2649
|
+
* .my-exercise-wrapper {
|
|
2650
|
+
* --chart-bar-color: #4f46e5;
|
|
2651
|
+
* --chart-bar-correct-color: #22c55e;
|
|
2652
|
+
* --chart-bar-wrong-color: #ef4444;
|
|
2653
|
+
* --chart-height: 320px;
|
|
2654
|
+
* }
|
|
2655
|
+
*
|
|
2656
|
+
* `--chart-height` is the exception: bar charts write it inline, and pictographs
|
|
2657
|
+
* derive theirs from `--picto-cell-size` / `--picto-cell-gap`, so resize a
|
|
2658
|
+
* pictograph through those two tokens rather than through `--chart-height`.
|
|
2659
|
+
*/
|
|
2660
|
+
|
|
2661
|
+
/* ── Token definitions (inside renderer scope) ─────────────────────────────── */
|
|
2662
|
+
|
|
2663
|
+
.math-exercise-renderer {
|
|
2664
|
+
/* Bar colours */
|
|
2665
|
+
--chart-bar-color: var(--exercise-accent, #705DC0);
|
|
2666
|
+
--chart-bar-correct-color: var(--exercise-correct, #22c55e);
|
|
2667
|
+
--chart-bar-wrong-color: var(--exercise-incorrect, #ef4444);
|
|
2668
|
+
|
|
2669
|
+
/* Axis / grid */
|
|
2670
|
+
--chart-grid-color: #e5e5e5;
|
|
2671
|
+
--chart-axis-color: var(--exercise-accent, #705DC0);
|
|
2672
|
+
--chart-axis-width: 2.35rem; /* width of the Y-axis label column */
|
|
2673
|
+
|
|
2674
|
+
/* Sizing */
|
|
2675
|
+
--chart-height: clamp(13rem, 34vw, 18rem);
|
|
2676
|
+
--chart-bar-slot-width: clamp(4.25rem, 11vw, 6rem);
|
|
2677
|
+
--chart-bar-width: clamp(2.7rem, 7vw, 4.1rem);
|
|
2678
|
+
--chart-bar-gap: clamp(0.65rem, 2.5vw, 1.5rem);
|
|
2679
|
+
--chart-content-width: 24rem;
|
|
2680
|
+
|
|
2681
|
+
/* Pictograph cells (fixed size — the plot height is derived from these) */
|
|
2682
|
+
--picto-cell-size: 2.6rem;
|
|
2683
|
+
--picto-cell-gap: 2px;
|
|
2684
|
+
|
|
2685
|
+
--chart-border-radius: 8px 8px 0 0;
|
|
2686
|
+
|
|
2687
|
+
/* Typography */
|
|
2688
|
+
--chart-font-size: clamp(0.78rem, 1.7vw, 1rem);
|
|
2689
|
+
--chart-label-font-size: clamp(0.85rem, 1.8vw, 1.08rem);
|
|
2690
|
+
--chart-font-weight: 500;
|
|
2691
|
+
--chart-label-min-height: 2.4em;
|
|
2692
|
+
|
|
2693
|
+
/* Handle */
|
|
2694
|
+
--chart-handle-size: clamp(0.9rem, 2vw, 1.15rem);
|
|
2695
|
+
}
|
|
2696
|
+
|
|
2697
|
+
/* ── Chart container (wraps title + chart grid) ────────────────────────────── */
|
|
2698
|
+
|
|
2699
|
+
.chart-container {
|
|
2700
|
+
display: flex;
|
|
2701
|
+
flex-direction: column;
|
|
2702
|
+
align-items: center;
|
|
2703
|
+
width: 100%;
|
|
2704
|
+
max-width: 560px;
|
|
2705
|
+
margin-block: 1rem;
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
.chart-title {
|
|
2709
|
+
grid-column: 3;
|
|
2710
|
+
grid-row: 1;
|
|
2711
|
+
align-self: end;
|
|
2712
|
+
font-size: var(--chart-label-font-size);
|
|
2713
|
+
font-weight: 600;
|
|
2714
|
+
color: var(--exercise-accent, #6c5fc7);
|
|
2715
|
+
text-align: center;
|
|
2716
|
+
padding-block: 0.5rem 0.4rem;
|
|
2717
|
+
overflow-wrap: break-word;
|
|
2718
|
+
white-space: normal;
|
|
2719
|
+
}
|
|
2720
|
+
|
|
2721
|
+
.chart-title,
|
|
2722
|
+
.chart-plot,
|
|
2723
|
+
.chart-axis-x-numeric,
|
|
2724
|
+
.chart-axis-title--x-category,
|
|
2725
|
+
.chart-axis-x {
|
|
2726
|
+
width: var(--chart-content-width);
|
|
2727
|
+
min-width: var(--chart-content-width);
|
|
2728
|
+
}
|
|
2729
|
+
|
|
2730
|
+
/* ── Root container ─────────────────────────────────────────────────────────── */
|
|
2731
|
+
|
|
2732
|
+
.chart-scroll {
|
|
2733
|
+
width: 100%;
|
|
2734
|
+
}
|
|
2735
|
+
|
|
2736
|
+
.chart {
|
|
2737
|
+
display: grid;
|
|
2738
|
+
/* columns: [y-title] [y-axis] [plot] */
|
|
2739
|
+
grid-template-columns: auto var(--chart-axis-width) 1fr;
|
|
2740
|
+
grid-template-rows: auto 1fr auto auto; /* title/padding | plot | x labels | x title */
|
|
2741
|
+
align-items: end;
|
|
2742
|
+
width: max-content;
|
|
2743
|
+
min-width: 0;
|
|
2744
|
+
margin-inline: auto;
|
|
2745
|
+
padding-block-start: calc(var(--chart-font-size) * 0.75);
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
/* Hidden axes: remove the matching plot-border axis line. */
|
|
2749
|
+
|
|
2750
|
+
.chart.chart--no-xaxis .chart-plot {
|
|
2751
|
+
border-bottom: none;
|
|
2752
|
+
}
|
|
2753
|
+
|
|
2754
|
+
.chart.chart--no-yaxis .chart-plot {
|
|
2755
|
+
border-left: none;
|
|
2756
|
+
border-inline-start: none;
|
|
2757
|
+
}
|
|
2758
|
+
|
|
2759
|
+
/* Vertical chart with no Y axis — collapse the Y-axis columns as well. */
|
|
2760
|
+
|
|
2761
|
+
.chart--no-yaxis:not(.chart--horizontal) {
|
|
2762
|
+
grid-template-columns: 1fr;
|
|
2763
|
+
}
|
|
2764
|
+
|
|
2765
|
+
/* ── Y axis ─────────────────────────────────────────────────────────────────── */
|
|
2766
|
+
|
|
2767
|
+
.chart-axis-tick-y,
|
|
2768
|
+
.chart-axis-tick-x-num {
|
|
2769
|
+
position: absolute;
|
|
2770
|
+
font-size: var(--chart-font-size);
|
|
2771
|
+
font-weight: var(--chart-font-weight);
|
|
2772
|
+
color: var(--chart-axis-color);
|
|
2773
|
+
line-height: 1;
|
|
2774
|
+
white-space: nowrap;
|
|
2775
|
+
pointer-events: none;
|
|
2776
|
+
user-select: none;
|
|
2777
|
+
}
|
|
2778
|
+
|
|
2779
|
+
.chart-axis-y {
|
|
2780
|
+
grid-column: 2;
|
|
2781
|
+
grid-row: 2;
|
|
2782
|
+
position: relative;
|
|
2783
|
+
height: var(--chart-height);
|
|
2784
|
+
width: var(--chart-axis-width);
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2787
|
+
.chart-axis-tick-y {
|
|
2788
|
+
right: 0.45rem;
|
|
2789
|
+
transform: translateY(50%);
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
/* ── Plot area ──────────────────────────────────────────────────────────────── */
|
|
2793
|
+
|
|
2794
|
+
.chart-plot {
|
|
2795
|
+
grid-column: 3;
|
|
2796
|
+
grid-row: 2;
|
|
2797
|
+
position: relative;
|
|
2798
|
+
height: var(--chart-height);
|
|
2799
|
+
border-left: 2px solid var(--chart-axis-color);
|
|
2800
|
+
border-bottom: 2px solid var(--chart-axis-color);
|
|
2801
|
+
overflow: hidden;
|
|
2802
|
+
}
|
|
2803
|
+
|
|
2804
|
+
/* ── Grid lines ─────────────────────────────────────────────────────────────── */
|
|
2805
|
+
|
|
2806
|
+
.chart-gridline {
|
|
2807
|
+
position: absolute;
|
|
2808
|
+
inset-inline: 0;
|
|
2809
|
+
height: 1px;
|
|
2810
|
+
background: var(--chart-grid-color);
|
|
2811
|
+
pointer-events: none;
|
|
2812
|
+
}
|
|
2813
|
+
|
|
2814
|
+
/* ── Bars container inside plot ─────────────────────────────────────────────── */
|
|
2815
|
+
|
|
2816
|
+
.chart-bars {
|
|
2817
|
+
position: absolute;
|
|
2818
|
+
inset: 0;
|
|
2819
|
+
display: flex;
|
|
2820
|
+
align-items: flex-end;
|
|
2821
|
+
justify-content: center;
|
|
2822
|
+
padding-inline: var(--chart-bar-gap);
|
|
2823
|
+
gap: var(--chart-bar-gap);
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
/* ── Single bar wrapper ─────────────────────────────────────────────────────── */
|
|
2827
|
+
|
|
2828
|
+
.chart-bar-wrapper {
|
|
2829
|
+
flex: 0 0 var(--chart-bar-slot-width);
|
|
2830
|
+
width: var(--chart-bar-slot-width);
|
|
2831
|
+
display: flex;
|
|
2832
|
+
flex-direction: column;
|
|
2833
|
+
align-items: center;
|
|
2834
|
+
height: 100%;
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2837
|
+
/* The full-height drag track (transparent, captures pointer events) */
|
|
2838
|
+
|
|
2839
|
+
.chart-bar-track {
|
|
2840
|
+
width: var(--chart-bar-width);
|
|
2841
|
+
height: 100%;
|
|
2842
|
+
position: relative;
|
|
2843
|
+
display: flex;
|
|
2844
|
+
flex-direction: column;
|
|
2845
|
+
justify-content: flex-end;
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2848
|
+
.chart-bar-track--interactive {
|
|
2849
|
+
touch-action: none; /* prevent scroll while dragging */
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
/* ── The filled bar ─────────────────────────────────────────────────────────── */
|
|
2853
|
+
|
|
2854
|
+
.chart-bar {
|
|
2855
|
+
width: 100%;
|
|
2856
|
+
/* Height driven by --bar-fill (0–1) × plot height; peek animation adds a
|
|
2857
|
+
temporary --peek-fill-offset to hint the bar is draggable */
|
|
2858
|
+
height: calc(min(1, var(--bar-fill, 0) + var(--peek-fill-offset, 0)) * 100%);
|
|
2859
|
+
background-color: var(--chart-bar-instance-color, var(--chart-bar-color));
|
|
2860
|
+
border-radius: var(--chart-border-radius);
|
|
2861
|
+
position: relative;
|
|
2862
|
+
transition: height 120ms ease, background-color 180ms ease, filter 180ms ease;
|
|
2863
|
+
}
|
|
2864
|
+
|
|
2865
|
+
.chart-bar--horizontal {
|
|
2866
|
+
border-radius: 0 8px 8px 0;
|
|
2867
|
+
}
|
|
2868
|
+
|
|
2869
|
+
/* Colour overrides based on validation */
|
|
2870
|
+
|
|
2871
|
+
.chart-bar-correct {
|
|
2872
|
+
background-color: var(--chart-bar-correct-color) !important;
|
|
2873
|
+
}
|
|
2874
|
+
|
|
2875
|
+
.chart-bar-incorrect {
|
|
2876
|
+
background-color: var(--chart-bar-wrong-color) !important;
|
|
2877
|
+
}
|
|
2878
|
+
|
|
2879
|
+
/* Hover tint on interactive bars */
|
|
2880
|
+
|
|
2881
|
+
.chart-bar-interactive {
|
|
2882
|
+
cursor: ns-resize;
|
|
2883
|
+
outline: none;
|
|
2884
|
+
touch-action: none;
|
|
2885
|
+
}
|
|
2886
|
+
|
|
2887
|
+
.chart--horizontal .chart-bar-interactive {
|
|
2888
|
+
cursor: ew-resize;
|
|
2889
|
+
}
|
|
2890
|
+
|
|
2891
|
+
.chart-bar-interactive.chart-bar-at-min {
|
|
2892
|
+
background-color: transparent;
|
|
2893
|
+
opacity: 0.7;
|
|
2894
|
+
}
|
|
2895
|
+
|
|
2896
|
+
.chart-bar-interactive.chart-bar-at-min.chart-bar-correct,
|
|
2897
|
+
.chart-bar-interactive.chart-bar-at-min.chart-bar-incorrect {
|
|
2898
|
+
background-color: transparent !important;
|
|
2899
|
+
}
|
|
2900
|
+
|
|
2901
|
+
.chart:not(.chart--horizontal) .chart-bar-interactive.chart-bar-at-min {
|
|
2902
|
+
min-height: var(--chart-handle-size);
|
|
2903
|
+
border-bottom: 3px dashed var(--chart-bar-instance-color, var(--chart-bar-color));
|
|
2904
|
+
}
|
|
2905
|
+
|
|
2906
|
+
.chart-bar-interactive:not(.chart-bar-correct):not(.chart-bar-incorrect):hover,
|
|
2907
|
+
.chart-bar-interactive:not(.chart-bar-correct):not(.chart-bar-incorrect):focus-visible,
|
|
2908
|
+
.chart-bar-interactive:not(.chart-bar-correct):not(.chart-bar-incorrect):active {
|
|
2909
|
+
background-color: color-mix(
|
|
2910
|
+
in srgb,
|
|
2911
|
+
var(--chart-bar-instance-color, var(--chart-bar-color)) 78%,
|
|
2912
|
+
white
|
|
2913
|
+
) !important;
|
|
2914
|
+
}
|
|
2915
|
+
|
|
2916
|
+
.chart-bar-interactive:focus-visible {
|
|
2917
|
+
box-shadow: 0 0 0 3px color-mix(in srgb, var(--chart-axis-color) 24%, transparent);
|
|
2918
|
+
}
|
|
2919
|
+
|
|
2920
|
+
.chart-bar-interactive.chart-bar-at-min:not(.chart-bar-correct):not(.chart-bar-incorrect):is(:hover, :focus-visible, :active) {
|
|
2921
|
+
background-color: transparent !important;
|
|
2922
|
+
opacity: 1;
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2925
|
+
.chart:not(.chart--horizontal) .chart-bar-interactive.chart-bar-at-min.chart-bar-correct {
|
|
2926
|
+
border-bottom-color: var(--chart-bar-correct-color);
|
|
2927
|
+
}
|
|
2928
|
+
|
|
2929
|
+
.chart:not(.chart--horizontal) .chart-bar-interactive.chart-bar-at-min.chart-bar-correct .chart-bar-handle {
|
|
2930
|
+
color: var(--chart-bar-correct-color);
|
|
2931
|
+
opacity: 1;
|
|
2932
|
+
}
|
|
2933
|
+
|
|
2934
|
+
.chart:not(.chart--horizontal) .chart-bar-interactive.chart-bar-at-min.chart-bar-incorrect {
|
|
2935
|
+
border-bottom-color: var(--chart-bar-wrong-color);
|
|
2936
|
+
}
|
|
2937
|
+
|
|
2938
|
+
.chart:not(.chart--horizontal) .chart-bar-interactive.chart-bar-at-min.chart-bar-incorrect .chart-bar-handle {
|
|
2939
|
+
color: var(--chart-bar-wrong-color);
|
|
2940
|
+
opacity: 1;
|
|
2941
|
+
}
|
|
2942
|
+
|
|
2943
|
+
/* ── Drag handle ────────────────────────────────────────────────────────────── */
|
|
2944
|
+
|
|
2945
|
+
.chart-bar-handle {
|
|
2946
|
+
position: absolute;
|
|
2947
|
+
top: 0.15rem;
|
|
2948
|
+
left: 50%;
|
|
2949
|
+
transform: translateX(-50%);
|
|
2950
|
+
width: var(--chart-handle-size);
|
|
2951
|
+
height: var(--chart-handle-size);
|
|
2952
|
+
color: white;
|
|
2953
|
+
pointer-events: none;
|
|
2954
|
+
z-index: 1;
|
|
2955
|
+
display: flex;
|
|
2956
|
+
align-items: center;
|
|
2957
|
+
justify-content: center;
|
|
2958
|
+
}
|
|
2959
|
+
|
|
2960
|
+
.chart-bar-handle svg {
|
|
2961
|
+
width: 100%;
|
|
2962
|
+
height: 100%;
|
|
2963
|
+
}
|
|
2964
|
+
|
|
2965
|
+
.chart:not(.chart--horizontal) .chart-bar-interactive.chart-bar-at-min .chart-bar-handle {
|
|
2966
|
+
top: 50%;
|
|
2967
|
+
transform: translateX(-50%) translateY(-50%);
|
|
2968
|
+
color: var(--chart-bar-instance-color, var(--chart-bar-color));
|
|
2969
|
+
opacity: 0.75;
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
/* ── X axis numeric ticks (when categoryAxis is present) ───────────────────── */
|
|
2973
|
+
|
|
2974
|
+
.chart-axis-x-numeric {
|
|
2975
|
+
grid-column: 3;
|
|
2976
|
+
grid-row: 3;
|
|
2977
|
+
padding-top: 0.35rem;
|
|
2978
|
+
}
|
|
2979
|
+
|
|
2980
|
+
.chart-axis-x-numeric-ticks {
|
|
2981
|
+
position: relative;
|
|
2982
|
+
height: 1.4rem;
|
|
2983
|
+
overflow: visible;
|
|
2984
|
+
}
|
|
2985
|
+
|
|
2986
|
+
.chart-axis-tick-x-num {
|
|
2987
|
+
top: 0;
|
|
2988
|
+
transform: translateX(-50%);
|
|
2989
|
+
}
|
|
2990
|
+
|
|
2991
|
+
/* ── Axis titles (inline content from axis body { ... }) ────────────────────── */
|
|
2992
|
+
|
|
2993
|
+
.chart-axis-title {
|
|
2994
|
+
font-size: calc(var(--chart-font-size) * 0.9);
|
|
2995
|
+
color: var(--chart-axis-color);
|
|
2996
|
+
text-align: center;
|
|
2997
|
+
line-height: 1.2;
|
|
2998
|
+
}
|
|
2999
|
+
|
|
3000
|
+
.chart-axis-title--y,
|
|
3001
|
+
.chart-axis-title--y-h {
|
|
3002
|
+
align-self: center;
|
|
3003
|
+
justify-self: center;
|
|
3004
|
+
font-size: calc(var(--chart-font-size) * 0.85);
|
|
3005
|
+
writing-mode: vertical-rl;
|
|
3006
|
+
transform: rotate(180deg);
|
|
3007
|
+
white-space: nowrap;
|
|
3008
|
+
padding-inline: 0.2rem;
|
|
3009
|
+
}
|
|
3010
|
+
|
|
3011
|
+
.chart-axis-title--x,
|
|
3012
|
+
.chart-axis-title--x-category {
|
|
3013
|
+
font-size: calc(var(--chart-font-size) * 0.85);
|
|
3014
|
+
font-weight: var(--chart-font-weight);
|
|
3015
|
+
white-space: nowrap;
|
|
3016
|
+
}
|
|
3017
|
+
|
|
3018
|
+
.chart-axis-title--y {
|
|
3019
|
+
grid-column: 1;
|
|
3020
|
+
grid-row: 2 / 3;
|
|
3021
|
+
}
|
|
3022
|
+
|
|
3023
|
+
.chart-axis-title--x {
|
|
3024
|
+
display: block;
|
|
3025
|
+
margin-top: 0.35rem;
|
|
3026
|
+
}
|
|
3027
|
+
|
|
3028
|
+
/* X-axis title when bar labels are present (placed in grid row 4) */
|
|
3029
|
+
|
|
3030
|
+
.chart-axis-title--x-category {
|
|
3031
|
+
grid-column: 3;
|
|
3032
|
+
grid-row: 4;
|
|
3033
|
+
padding-block-start: 0.3rem;
|
|
3034
|
+
}
|
|
3035
|
+
|
|
3036
|
+
/* ── X axis (category or value labels row) ──────────────────────────────────── */
|
|
3037
|
+
|
|
3038
|
+
.chart-axis-x {
|
|
3039
|
+
grid-column: 3;
|
|
3040
|
+
grid-row: 3;
|
|
3041
|
+
display: flex;
|
|
3042
|
+
justify-content: center;
|
|
3043
|
+
padding-inline: var(--chart-bar-gap);
|
|
3044
|
+
gap: var(--chart-bar-gap);
|
|
3045
|
+
padding-top: 0.55rem;
|
|
3046
|
+
align-items: flex-start;
|
|
3047
|
+
}
|
|
3048
|
+
|
|
3049
|
+
.chart-axis-tick-x {
|
|
3050
|
+
flex: 0 0 var(--chart-bar-slot-width);
|
|
3051
|
+
min-width: 0;
|
|
3052
|
+
min-height: var(--chart-label-min-height);
|
|
3053
|
+
font-size: var(--chart-label-font-size);
|
|
3054
|
+
font-weight: var(--chart-font-weight);
|
|
3055
|
+
color: var(--chart-axis-color);
|
|
3056
|
+
line-height: 1.15;
|
|
3057
|
+
display: flex;
|
|
3058
|
+
justify-content: center;
|
|
3059
|
+
align-items: flex-start;
|
|
3060
|
+
}
|
|
3061
|
+
|
|
3062
|
+
.chart-axis-tick-x-inner {
|
|
3063
|
+
display: -webkit-box;
|
|
3064
|
+
-webkit-box-orient: vertical;
|
|
3065
|
+
-webkit-line-clamp: 3;
|
|
3066
|
+
line-clamp: 3;
|
|
3067
|
+
overflow: hidden;
|
|
3068
|
+
width: 100%;
|
|
3069
|
+
text-align: center;
|
|
3070
|
+
}
|
|
3071
|
+
|
|
3072
|
+
.chart-axis-tick-x .text-item {
|
|
3073
|
+
display: inline-block;
|
|
3074
|
+
max-width: 100%;
|
|
3075
|
+
overflow-wrap: anywhere;
|
|
3076
|
+
}
|
|
3077
|
+
|
|
3078
|
+
.chart-axis-tick-x .inline-input-droppable {
|
|
3079
|
+
max-width: 100%;
|
|
3080
|
+
}
|
|
3081
|
+
|
|
3082
|
+
.chart-axis-tick-x .inline-input,
|
|
3083
|
+
.chart-axis-tick-x .inline-input-chip {
|
|
3084
|
+
max-width: 100%;
|
|
3085
|
+
box-sizing: border-box;
|
|
3086
|
+
padding: 0.2rem 0.35rem;
|
|
3087
|
+
font-size: 0.82rem;
|
|
3088
|
+
line-height: 1.1;
|
|
3089
|
+
}
|
|
3090
|
+
|
|
3091
|
+
/* ═══════════════════════════════════════════════════════════════════════════
|
|
3092
|
+
HORIZONTAL BAR CHART (.chart--horizontal)
|
|
3093
|
+
Grid: [y-labels col] [plot col]
|
|
3094
|
+
[empty ] [x-axis row]
|
|
3095
|
+
═══════════════════════════════════════════════════════════════════════════ */
|
|
3096
|
+
|
|
3097
|
+
.chart--horizontal {
|
|
3098
|
+
grid-template-columns: auto auto 1fr;
|
|
3099
|
+
grid-template-rows: auto 1fr auto;
|
|
3100
|
+
align-items: start; /* override vertical align-items: end */
|
|
3101
|
+
}
|
|
3102
|
+
|
|
3103
|
+
/* In horizontal mode, chart-title goes above the plot column */
|
|
3104
|
+
|
|
3105
|
+
.chart--horizontal .chart-title {
|
|
3106
|
+
grid-column: 3;
|
|
3107
|
+
grid-row: 1;
|
|
3108
|
+
align-self: end;
|
|
3109
|
+
width: max(100%, var(--chart-h-value-width, 16rem));
|
|
3110
|
+
}
|
|
3111
|
+
|
|
3112
|
+
/* ── Horizontal: Y-side category labels ─────────────────────────────────── */
|
|
3113
|
+
|
|
3114
|
+
.chart--horizontal .chart-axis-y--categories {
|
|
3115
|
+
grid-column: 2;
|
|
3116
|
+
grid-row: 2;
|
|
3117
|
+
display: flex;
|
|
3118
|
+
flex-direction: column;
|
|
3119
|
+
justify-content: flex-start;
|
|
3120
|
+
height: var(--chart-height);
|
|
3121
|
+
padding-block: var(--chart-bar-gap);
|
|
3122
|
+
gap: var(--chart-bar-gap);
|
|
3123
|
+
min-width: max-content;
|
|
3124
|
+
}
|
|
3125
|
+
|
|
3126
|
+
.chart--horizontal .chart-bar-y-label {
|
|
3127
|
+
flex: 0 0 var(--chart-bar-slot-width);
|
|
3128
|
+
height: var(--chart-bar-slot-width);
|
|
3129
|
+
display: flex;
|
|
3130
|
+
align-items: center;
|
|
3131
|
+
justify-content: flex-end;
|
|
3132
|
+
padding-inline-end: 0.6rem;
|
|
3133
|
+
padding-inline-start: 0.35rem;
|
|
3134
|
+
font-size: var(--chart-label-font-size);
|
|
3135
|
+
font-weight: var(--chart-font-weight);
|
|
3136
|
+
color: var(--exercise-text-primary, #1f2937);
|
|
3137
|
+
white-space: nowrap;
|
|
3138
|
+
}
|
|
3139
|
+
|
|
3140
|
+
/* ── Horizontal: plot area ───────────────────────────────────────────────── */
|
|
3141
|
+
|
|
3142
|
+
.chart--horizontal .chart-plot {
|
|
3143
|
+
grid-column: 3;
|
|
3144
|
+
grid-row: 2;
|
|
3145
|
+
width: max(100%, var(--chart-h-value-width, 16rem));
|
|
3146
|
+
border-inline-start: 2px solid var(--chart-axis-color);
|
|
3147
|
+
border-bottom: 2px solid var(--chart-axis-color);
|
|
3148
|
+
}
|
|
3149
|
+
|
|
3150
|
+
/* ── Horizontal: bars container ─────────────────────────────────────────── */
|
|
3151
|
+
|
|
3152
|
+
.chart--horizontal .chart-bars {
|
|
3153
|
+
flex-direction: column;
|
|
3154
|
+
align-items: flex-start;
|
|
3155
|
+
justify-content: flex-start;
|
|
3156
|
+
padding-inline: 0;
|
|
3157
|
+
padding-block: var(--chart-bar-gap);
|
|
3158
|
+
}
|
|
3159
|
+
|
|
3160
|
+
.chart--horizontal .chart-bar-wrapper {
|
|
3161
|
+
flex: 0 0 var(--chart-bar-slot-width);
|
|
3162
|
+
height: var(--chart-bar-slot-width);
|
|
3163
|
+
width: 100%;
|
|
3164
|
+
flex-direction: row;
|
|
3165
|
+
align-items: center;
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
.chart--horizontal .chart-bar-track {
|
|
3169
|
+
width: 100%;
|
|
3170
|
+
height: var(--chart-bar-width);
|
|
3171
|
+
flex-direction: row;
|
|
3172
|
+
justify-content: flex-start;
|
|
3173
|
+
}
|
|
3174
|
+
|
|
3175
|
+
/* Bar grows along X (width instead of height) */
|
|
3176
|
+
|
|
3177
|
+
.chart--horizontal .chart-bar {
|
|
3178
|
+
width: calc(min(1, var(--bar-fill, 0) + var(--peek-fill-offset, 0)) * 100%);
|
|
3179
|
+
height: 100%;
|
|
3180
|
+
transition: width 120ms ease, background-color 180ms ease, filter 180ms ease;
|
|
3181
|
+
}
|
|
3182
|
+
|
|
3183
|
+
/* Interactive handle for horizontal: same SVG rotated 90° → ">>" */
|
|
3184
|
+
|
|
3185
|
+
.chart--horizontal .chart-bar-handle {
|
|
3186
|
+
top: 50%;
|
|
3187
|
+
left: unset;
|
|
3188
|
+
right: 0.55rem;
|
|
3189
|
+
transform: translateY(-50%) rotate(90deg);
|
|
3190
|
+
}
|
|
3191
|
+
|
|
3192
|
+
.chart--horizontal .chart-bar-interactive.chart-bar-at-min {
|
|
3193
|
+
min-width: var(--chart-handle-size);
|
|
3194
|
+
border-left: 3px dashed var(--chart-bar-instance-color, var(--chart-bar-color));
|
|
3195
|
+
}
|
|
3196
|
+
|
|
3197
|
+
.chart--horizontal .chart-bar-interactive.chart-bar-at-min .chart-bar-handle {
|
|
3198
|
+
left: 50%;
|
|
3199
|
+
right: auto;
|
|
3200
|
+
top: 50%;
|
|
3201
|
+
transform: translateX(-50%) translateY(-50%) rotate(90deg);
|
|
3202
|
+
color: var(--chart-bar-instance-color, var(--chart-bar-color));
|
|
3203
|
+
opacity: 0.75;
|
|
3204
|
+
}
|
|
3205
|
+
|
|
3206
|
+
.chart--horizontal .chart-bar-interactive.chart-bar-at-min.chart-bar-correct {
|
|
3207
|
+
border-left-color: var(--chart-bar-correct-color);
|
|
3208
|
+
}
|
|
3209
|
+
|
|
3210
|
+
.chart--horizontal .chart-bar-interactive.chart-bar-at-min.chart-bar-correct .chart-bar-handle {
|
|
3211
|
+
color: var(--chart-bar-correct-color);
|
|
3212
|
+
opacity: 1;
|
|
3213
|
+
}
|
|
3214
|
+
|
|
3215
|
+
.chart--horizontal .chart-bar-interactive.chart-bar-at-min.chart-bar-incorrect {
|
|
3216
|
+
border-left-color: var(--chart-bar-wrong-color);
|
|
3217
|
+
}
|
|
3218
|
+
|
|
3219
|
+
.chart--horizontal .chart-bar-interactive.chart-bar-at-min.chart-bar-incorrect .chart-bar-handle {
|
|
3220
|
+
color: var(--chart-bar-wrong-color);
|
|
3221
|
+
opacity: 1;
|
|
3222
|
+
}
|
|
3223
|
+
|
|
3224
|
+
/* ── Horizontal: grid (vertical lines) ──────────────────────────────────── */
|
|
3225
|
+
|
|
3226
|
+
.chart--horizontal .chart-gridline {
|
|
3227
|
+
width: 1px;
|
|
3228
|
+
height: 100%;
|
|
3229
|
+
top: 0;
|
|
3230
|
+
bottom: 0;
|
|
3231
|
+
inset-inline: unset;
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3234
|
+
/* ── Horizontal: numeric X axis (below plot) ─────────────────────────────── */
|
|
3235
|
+
|
|
3236
|
+
.chart--horizontal .chart-axis-x-numeric {
|
|
3237
|
+
grid-column: 3;
|
|
3238
|
+
grid-row: 3;
|
|
3239
|
+
width: max(100%, var(--chart-h-value-width, 16rem));
|
|
3240
|
+
}
|
|
3241
|
+
|
|
3242
|
+
/* ── Horizontal: Y-axis title (shown above labels column) ───────────────── */
|
|
3243
|
+
|
|
3244
|
+
.chart-axis-title--y-h {
|
|
3245
|
+
grid-column: 1;
|
|
3246
|
+
grid-row: 2;
|
|
3247
|
+
}
|
|
3248
|
+
|
|
3249
|
+
/* ── Draggable-hint peek animation ──────────────────────────────────────────── */
|
|
3250
|
+
|
|
3251
|
+
@property --peek-fill-offset { syntax: '<number>'; inherits: false; initial-value: 0; }
|
|
3252
|
+
|
|
3253
|
+
@keyframes chart-bar-peek {
|
|
3254
|
+
0%, 100% { --peek-fill-offset: 0; }
|
|
3255
|
+
40% { --peek-fill-offset: 0.15; }
|
|
3256
|
+
70% { --peek-fill-offset: 0.05; }
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3259
|
+
@keyframes chart-bar-peek-zero {
|
|
3260
|
+
0%, 100% { --peek-fill-offset: 0; background-color: transparent; opacity: 0.7; }
|
|
3261
|
+
40% { --peek-fill-offset: 0.15; background-color: color-mix(in srgb, var(--chart-bar-instance-color, var(--chart-bar-color)) 72%, transparent); opacity: 0.95; }
|
|
3262
|
+
70% { --peek-fill-offset: 0.05; background-color: color-mix(in srgb, var(--chart-bar-instance-color, var(--chart-bar-color)) 52%, transparent); opacity: 0.82; }
|
|
3263
|
+
}
|
|
3264
|
+
|
|
3265
|
+
@keyframes chart-bar-peek-handle-v {
|
|
3266
|
+
0%, 100% { top: 50%; transform: translateX(-50%) translateY(-50%); color: var(--chart-bar-instance-color, var(--chart-bar-color)); opacity: 0.75; }
|
|
3267
|
+
40%, 70% { top: 0.15rem; transform: translateX(-50%); color: white; opacity: 1; }
|
|
3268
|
+
}
|
|
3269
|
+
|
|
3270
|
+
@keyframes chart-bar-peek-handle-h {
|
|
3271
|
+
0%, 100% { left: 50%; transform: translateX(-50%) translateY(-50%) rotate(90deg); color: var(--chart-bar-instance-color, var(--chart-bar-color)); opacity: 0.75; }
|
|
3272
|
+
40%, 70% { left: calc(100% - 0.55rem); transform: translateX(-50%) translateY(-50%) rotate(90deg); color: white; opacity: 1; }
|
|
3273
|
+
}
|
|
3274
|
+
|
|
3275
|
+
.chart-bar--peek { transition: filter 180ms ease; animation: chart-bar-peek 0.7s ease-in-out 0.3s 2 both; }
|
|
3276
|
+
|
|
3277
|
+
.chart-bar-at-min.chart-bar--peek { animation: chart-bar-peek-zero 0.7s ease-in-out 0.3s 2 both; }
|
|
3278
|
+
|
|
3279
|
+
.chart:not(.chart--horizontal) .chart-bar-at-min.chart-bar--peek .chart-bar-handle { animation: chart-bar-peek-handle-v 0.7s ease-in-out 0.3s 2 both; }
|
|
3280
|
+
|
|
3281
|
+
.chart--horizontal .chart-bar-at-min.chart-bar--peek .chart-bar-handle { animation: chart-bar-peek-handle-h 0.7s ease-in-out 0.3s 2 both; }
|
|
3282
|
+
|
|
3283
|
+
/* ── Pictograph chart ────────────────────────────────────────────────────────── */
|
|
3284
|
+
|
|
3285
|
+
/* A vertical pictograph's --chart-height is emitted inline by
|
|
3286
|
+
computePictographChartStyle(), because the inline --chart-height that every chart
|
|
3287
|
+
already carries would outrank any rule written here. Overriding these two tokens
|
|
3288
|
+
still resizes the plot: the inline height is a calc() over them. */
|
|
3289
|
+
|
|
3290
|
+
/* The hint animation lifts and scales an icon past its cell, so the stack must not clip. */
|
|
3291
|
+
|
|
3292
|
+
.chart--pictograph .chart-plot {
|
|
3293
|
+
overflow: visible;
|
|
3294
|
+
}
|
|
3295
|
+
|
|
3296
|
+
.chart-picto-column-wrapper {
|
|
3297
|
+
display: flex;
|
|
3298
|
+
flex-direction: column;
|
|
3299
|
+
align-items: center;
|
|
3300
|
+
justify-content: flex-end;
|
|
3301
|
+
height: 100%;
|
|
3302
|
+
}
|
|
3303
|
+
|
|
3304
|
+
.chart-picto-column-wrapper--h {
|
|
3305
|
+
flex-direction: row;
|
|
3306
|
+
justify-content: flex-start;
|
|
3307
|
+
align-items: center;
|
|
3308
|
+
height: auto;
|
|
3309
|
+
width: 100%;
|
|
3310
|
+
}
|
|
3311
|
+
|
|
3312
|
+
.chart-picto-cells {
|
|
3313
|
+
display: flex;
|
|
3314
|
+
flex-direction: column-reverse;
|
|
3315
|
+
gap: var(--picto-cell-gap);
|
|
3316
|
+
}
|
|
3317
|
+
|
|
3318
|
+
.chart-picto-cells--h {
|
|
3319
|
+
flex-direction: row;
|
|
3320
|
+
gap: var(--picto-cell-gap);
|
|
3321
|
+
}
|
|
3322
|
+
|
|
3323
|
+
.picto-cell {
|
|
3324
|
+
width: var(--picto-cell-size);
|
|
3325
|
+
height: var(--picto-cell-size);
|
|
3326
|
+
display: flex;
|
|
3327
|
+
align-items: center;
|
|
3328
|
+
justify-content: center;
|
|
3329
|
+
border-radius: 4px;
|
|
3330
|
+
}
|
|
3331
|
+
|
|
3332
|
+
.picto-cell img {
|
|
3333
|
+
width: 85%;
|
|
3334
|
+
height: 85%;
|
|
3335
|
+
object-fit: contain;
|
|
3336
|
+
transition: filter 150ms ease, transform 150ms ease;
|
|
3337
|
+
}
|
|
3338
|
+
|
|
3339
|
+
.picto-cell--inactive img {
|
|
3340
|
+
filter: grayscale(100%) brightness(0.9);
|
|
3341
|
+
}
|
|
3342
|
+
|
|
3343
|
+
.picto-cell--interactive {
|
|
3344
|
+
cursor: pointer;
|
|
3345
|
+
}
|
|
3346
|
+
|
|
3347
|
+
.picto-cell--locked {
|
|
3348
|
+
cursor: default;
|
|
3349
|
+
}
|
|
3350
|
+
|
|
3351
|
+
.picto-cell--interactive:focus-visible {
|
|
3352
|
+
outline: 2px solid var(--chart-bar-color, #6366f1);
|
|
3353
|
+
outline-offset: 1px;
|
|
3354
|
+
}
|
|
3355
|
+
|
|
3356
|
+
/* Hover sur cellule ACTIVE : légère luminosité, reste clairement actif */
|
|
3357
|
+
|
|
3358
|
+
.picto-cell--interactive:not(.picto-cell--inactive):hover img {
|
|
3359
|
+
filter: brightness(1.18);
|
|
3360
|
+
}
|
|
3361
|
+
|
|
3362
|
+
/* Hover sur cellule INACTIVE : reste grise, juste légèrement plus lumineuse */
|
|
3363
|
+
|
|
3364
|
+
.picto-cell--inactive.picto-cell--interactive:hover img {
|
|
3365
|
+
filter: grayscale(100%) brightness(1.12);
|
|
3366
|
+
}
|
|
3367
|
+
|
|
3368
|
+
.picto-column--correct .picto-cell:not(.picto-cell--inactive) img {
|
|
3369
|
+
filter: drop-shadow(0 0 3px var(--exercise-correct, #22c55e));
|
|
3370
|
+
}
|
|
3371
|
+
|
|
3372
|
+
.picto-column--incorrect .picto-cell:not(.picto-cell--inactive) img {
|
|
3373
|
+
filter: drop-shadow(0 0 3px var(--exercise-incorrect, #ef4444));
|
|
3374
|
+
}
|
|
3375
|
+
|
|
3376
|
+
/* ── Pictograph validation animations ──────────────────────────────────────── */
|
|
3377
|
+
|
|
3378
|
+
@keyframes picto-pop {
|
|
3379
|
+
0% { transform: scale(1); }
|
|
3380
|
+
35% { transform: scale(1.32); }
|
|
3381
|
+
60% { transform: scale(0.91); }
|
|
3382
|
+
80% { transform: scale(1.07); }
|
|
3383
|
+
100% { transform: scale(1); }
|
|
3384
|
+
}
|
|
3385
|
+
|
|
3386
|
+
@keyframes picto-jiggle {
|
|
3387
|
+
0%, 100% { transform: translate(0, 0) rotate(0deg); }
|
|
3388
|
+
12% { transform: translate(-5px, 0) rotate(-10deg); }
|
|
3389
|
+
25% { transform: translate(5px, 0) rotate(10deg); }
|
|
3390
|
+
37% { transform: translate(-4px, 0) rotate(-7deg); }
|
|
3391
|
+
50% { transform: translate(4px, 0) rotate(7deg); }
|
|
3392
|
+
62% { transform: translate(-2px, 0) rotate(-4deg); }
|
|
3393
|
+
75% { transform: translate(2px, 0) rotate(4deg); }
|
|
3394
|
+
87% { transform: translate(-1px, 0) rotate(-2deg); }
|
|
3395
|
+
}
|
|
3396
|
+
|
|
3397
|
+
.picto-cell--pop img {
|
|
3398
|
+
animation: picto-pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) both;
|
|
3399
|
+
}
|
|
3400
|
+
|
|
3401
|
+
.picto-cell--jiggle img {
|
|
3402
|
+
animation: picto-jiggle 0.55s ease-in-out both;
|
|
3403
|
+
}
|
|
3404
|
+
|
|
3405
|
+
@keyframes picto-hint {
|
|
3406
|
+
0%, 100% { transform: translateY(0) scale(1); }
|
|
3407
|
+
30% { transform: translateY(-5px) scale(1.12); }
|
|
3408
|
+
55% { transform: translateY(-1px) scale(1.04); }
|
|
3409
|
+
75% { transform: translateY(-3px) scale(1.09); }
|
|
3410
|
+
}
|
|
3411
|
+
|
|
3412
|
+
.picto-cell--hint img {
|
|
3413
|
+
animation: picto-hint 0.65s cubic-bezier(0.34, 1.2, 0.64, 1) both;
|
|
3414
|
+
}
|
|
3415
|
+
|
|
3416
|
+
/* ── Pictograph cell grid lines ─────────────────────────────────────────────── */
|
|
3417
|
+
|
|
3418
|
+
.picto-gridline {
|
|
3419
|
+
position: absolute;
|
|
3420
|
+
pointer-events: none;
|
|
3421
|
+
background: var(--chart-grid-color);
|
|
3422
|
+
}
|
|
3423
|
+
|
|
3424
|
+
/* Horizontal separators (between rows of picto cells) */
|
|
3425
|
+
|
|
3426
|
+
.picto-gridline--row {
|
|
3427
|
+
inset-inline: 0;
|
|
3428
|
+
height: 1px;
|
|
3429
|
+
}
|
|
3430
|
+
|
|
3431
|
+
/* Vertical separators (between picto columns) */
|
|
3432
|
+
|
|
3433
|
+
.picto-gridline--col {
|
|
3434
|
+
top: 0;
|
|
3435
|
+
bottom: 0;
|
|
3436
|
+
width: 1px;
|
|
3437
|
+
}
|
|
3438
|
+
|
|
2633
3439
|
/* Responsive Overrides - must be last */
|
|
2634
3440
|
|
|
2635
3441
|
/**
|