@visns-studio/visns-components 6.32.2 → 6.34.0
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/README.md +504 -0
- package/package.json +1 -1
- package/src/components/DataGrid.jsx +44 -2
- package/src/components/Field.jsx +32 -0
- package/src/components/Form.jsx +39 -2
- package/src/components/Navigation.jsx +353 -43
- package/src/components/Notification.jsx +13 -2
- package/src/components/TableFilter.jsx +14 -2
- package/src/components/auth/Login.jsx +9 -2
- package/src/components/auth/PasskeyEnrolPrompt.jsx +269 -0
- package/src/components/auth/Profile.jsx +422 -26
- package/src/components/auth/authEndpoints.js +43 -0
- package/src/components/auth/passkeyClient.js +102 -0
- package/src/components/auth/passkeyPrompt.js +408 -0
- package/src/components/auth/profileLayout.js +45 -0
- package/src/components/controls/DataGridSearch.jsx +16 -2
- package/src/components/controls/DataGridSortSheet.jsx +2 -0
- package/src/components/generic/ActionButtons.jsx +1 -1
- package/src/components/generic/GenericAuth.jsx +197 -21
- package/src/components/generic/GenericDetail.jsx +95 -3
- package/src/components/generic/GenericMain.jsx +7 -0
- package/src/components/generic/StandardModal.jsx +71 -158
- package/src/components/sms/SmsCampaigns.jsx +2487 -0
- package/src/components/sms/SmsInbox.jsx +18 -0
- package/src/components/sms/SmsThreadPanel.jsx +20 -0
- package/src/components/sms/smsEndpoints.js +23 -0
- package/src/components/styles/DataGrid.module.scss +22 -0
- package/src/components/styles/Form.module.scss +100 -2
- package/src/components/styles/Navigation.module.scss +354 -15
- package/src/components/styles/Notification.module.scss +140 -8
- package/src/components/styles/PasskeyEnrolPrompt.module.scss +105 -0
- package/src/components/styles/Profile.module.scss +157 -0
- package/src/components/styles/Sms.module.scss +451 -0
- package/src/components/styles/StandardModal.module.scss +273 -0
- package/src/components/styles/global.css +24 -5
- package/src/components/utils/navCollapsed.js +201 -0
- package/src/components/utils/rowActionSettings.js +76 -0
- package/src/components/utils/usePasskeysEnabled.js +84 -0
- package/src/components/utils/useShellLayout.js +131 -0
- package/src/index.js +103 -1
- package/src/utils/rememberTab.js +70 -0
|
@@ -1825,6 +1825,26 @@ $sms-mono: 'SFMono-Regular', 'Menlo', 'Consolas', monospace;
|
|
|
1825
1825
|
// One card: the text on top, every control in a bar along its bottom edge.
|
|
1826
1826
|
// Buttons beside a textarea line up with nothing once the box grows; a bar
|
|
1827
1827
|
// inside the same border always reads as part of the message being written.
|
|
1828
|
+
// The opted-out line, above the composer and nothing else.
|
|
1829
|
+
//
|
|
1830
|
+
// Muted on purpose. It is a fact worth knowing before typing, not a warning
|
|
1831
|
+
// about what is being typed — and everything below it stays live, because an
|
|
1832
|
+
// opt-out is about bulk sends and this is a person answering a person.
|
|
1833
|
+
.optedOutNote {
|
|
1834
|
+
display: flex;
|
|
1835
|
+
gap: 0.4rem;
|
|
1836
|
+
align-items: center;
|
|
1837
|
+
margin: 0 0 0.45rem;
|
|
1838
|
+
color: var(--s-muted);
|
|
1839
|
+
font-size: 0.76rem;
|
|
1840
|
+
line-height: 1.4;
|
|
1841
|
+
|
|
1842
|
+
svg {
|
|
1843
|
+
flex-shrink: 0;
|
|
1844
|
+
color: var(--s-muted);
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1828
1848
|
.composerBox {
|
|
1829
1849
|
display: flex;
|
|
1830
1850
|
flex-direction: column;
|
|
@@ -2776,3 +2796,434 @@ $sms-mono: 'SFMono-Regular', 'Menlo', 'Consolas', monospace;
|
|
|
2776
2796
|
border-radius: var(--s-br);
|
|
2777
2797
|
}
|
|
2778
2798
|
}
|
|
2799
|
+
|
|
2800
|
+
// ---------------------------------------------------------------------------
|
|
2801
|
+
// SmsCampaigns — the list, the three-step flow, one campaign, the opt-outs
|
|
2802
|
+
// ---------------------------------------------------------------------------
|
|
2803
|
+
//
|
|
2804
|
+
// The page mounts inside `.settings`, so it inherits the tokens and the
|
|
2805
|
+
// padding the messaging settings screen already has: a campaign list is a
|
|
2806
|
+
// table of records with an action bar over it, which is exactly what that
|
|
2807
|
+
// screen is. Everything below is the parts a settings screen has no vocabulary
|
|
2808
|
+
// for — a progress bar, a step rail, a drop target and a preview column.
|
|
2809
|
+
|
|
2810
|
+
// "Sending" is not a warning.
|
|
2811
|
+
//
|
|
2812
|
+
// A campaign doing precisely what it was told to do drawn in amber teaches
|
|
2813
|
+
// people to stop reading the chips, and then the paused one — the state where
|
|
2814
|
+
// nothing is going out and somebody has to act — reads the same as the healthy
|
|
2815
|
+
// one. So it takes the brand tint: visibly live, and visibly not a problem.
|
|
2816
|
+
.campaignPillLive {
|
|
2817
|
+
background: var(--s-tint);
|
|
2818
|
+
color: var(--s-primary);
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
// The flag on a number the browser cannot read as one. A pill inside a cell,
|
|
2822
|
+
// so it needs the gap the cell does not give it.
|
|
2823
|
+
.campaignFlag {
|
|
2824
|
+
margin-left: 0.4rem;
|
|
2825
|
+
}
|
|
2826
|
+
|
|
2827
|
+
/* ------------------------------------------------------------- progress */
|
|
2828
|
+
|
|
2829
|
+
.campaignProgress {
|
|
2830
|
+
display: flex;
|
|
2831
|
+
gap: 0.5rem;
|
|
2832
|
+
align-items: center;
|
|
2833
|
+
min-width: 0;
|
|
2834
|
+
}
|
|
2835
|
+
|
|
2836
|
+
// The track is fixed and the fill is a percentage of it. Both are needed: a
|
|
2837
|
+
// bar that shrinks to its own fill has no "how much is left" in it, which is
|
|
2838
|
+
// the only question a progress bar answers.
|
|
2839
|
+
.campaignBar {
|
|
2840
|
+
flex: 1 1 auto;
|
|
2841
|
+
box-sizing: border-box;
|
|
2842
|
+
min-width: 90px;
|
|
2843
|
+
height: 6px;
|
|
2844
|
+
border-radius: 999px;
|
|
2845
|
+
background: color-mix(in srgb, var(--s-paragraph) 12%, var(--s-background));
|
|
2846
|
+
overflow: hidden;
|
|
2847
|
+
}
|
|
2848
|
+
|
|
2849
|
+
.campaignBarFill {
|
|
2850
|
+
display: block;
|
|
2851
|
+
height: 100%;
|
|
2852
|
+
border-radius: 999px;
|
|
2853
|
+
background: var(--s-primary);
|
|
2854
|
+
// Short, and only ever forward: the number behind it moves a few percent
|
|
2855
|
+
// every poll, and an unanimated jump reads as the page reloading.
|
|
2856
|
+
transition: width 0.3s ease;
|
|
2857
|
+
}
|
|
2858
|
+
|
|
2859
|
+
.campaignProgressCount {
|
|
2860
|
+
flex: 0 0 auto;
|
|
2861
|
+
color: var(--s-muted);
|
|
2862
|
+
font-size: 0.78rem;
|
|
2863
|
+
font-variant-numeric: tabular-nums;
|
|
2864
|
+
white-space: nowrap;
|
|
2865
|
+
}
|
|
2866
|
+
|
|
2867
|
+
// The bar needs room in a table cell that would otherwise size to its text.
|
|
2868
|
+
.campaignProgressCell {
|
|
2869
|
+
min-width: 170px;
|
|
2870
|
+
}
|
|
2871
|
+
|
|
2872
|
+
/* --------------------------------------------------------------- wizard */
|
|
2873
|
+
|
|
2874
|
+
.campaignWizard,
|
|
2875
|
+
.campaignDetail {
|
|
2876
|
+
display: flex;
|
|
2877
|
+
flex-direction: column;
|
|
2878
|
+
gap: 1rem;
|
|
2879
|
+
}
|
|
2880
|
+
|
|
2881
|
+
// The step rail. Numbered, because "Message" on its own does not say whether
|
|
2882
|
+
// it comes before or after the list — and the numbers are what the Back button
|
|
2883
|
+
// is moving between.
|
|
2884
|
+
.campaignSteps {
|
|
2885
|
+
display: flex;
|
|
2886
|
+
flex-wrap: wrap;
|
|
2887
|
+
gap: 0.4rem 1.25rem;
|
|
2888
|
+
margin: 0;
|
|
2889
|
+
padding: 0;
|
|
2890
|
+
list-style: none;
|
|
2891
|
+
}
|
|
2892
|
+
|
|
2893
|
+
.campaignStep {
|
|
2894
|
+
display: inline-flex;
|
|
2895
|
+
gap: 0.45rem;
|
|
2896
|
+
align-items: center;
|
|
2897
|
+
color: var(--s-muted);
|
|
2898
|
+
font-size: 0.82rem;
|
|
2899
|
+
font-weight: 600;
|
|
2900
|
+
}
|
|
2901
|
+
|
|
2902
|
+
.campaignStepOn {
|
|
2903
|
+
color: var(--s-paragraph);
|
|
2904
|
+
|
|
2905
|
+
.campaignStepNumber {
|
|
2906
|
+
border-color: var(--s-primary);
|
|
2907
|
+
background: var(--s-primary);
|
|
2908
|
+
color: #fff;
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2912
|
+
.campaignStepNumber {
|
|
2913
|
+
display: inline-flex;
|
|
2914
|
+
flex: 0 0 auto;
|
|
2915
|
+
align-items: center;
|
|
2916
|
+
justify-content: center;
|
|
2917
|
+
box-sizing: border-box;
|
|
2918
|
+
width: 22px;
|
|
2919
|
+
height: 22px;
|
|
2920
|
+
border: 1px solid var(--s-line);
|
|
2921
|
+
border-radius: 50%;
|
|
2922
|
+
background: var(--s-background);
|
|
2923
|
+
color: var(--s-muted);
|
|
2924
|
+
font-size: 0.74rem;
|
|
2925
|
+
font-weight: 700;
|
|
2926
|
+
font-variant-numeric: tabular-nums;
|
|
2927
|
+
}
|
|
2928
|
+
|
|
2929
|
+
// Two ways in, side by side and of equal weight — neither is the "proper" one.
|
|
2930
|
+
// They stack below the tablet breakpoint, where two columns of this leave the
|
|
2931
|
+
// paste box too narrow to see a line of `Name, number` in.
|
|
2932
|
+
.campaignSources {
|
|
2933
|
+
display: grid;
|
|
2934
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
2935
|
+
gap: 1rem;
|
|
2936
|
+
}
|
|
2937
|
+
|
|
2938
|
+
.campaignSource {
|
|
2939
|
+
display: flex;
|
|
2940
|
+
flex-direction: column;
|
|
2941
|
+
gap: 0.6rem;
|
|
2942
|
+
box-sizing: border-box;
|
|
2943
|
+
padding: 0.85rem 1rem;
|
|
2944
|
+
border: 1px solid var(--s-line);
|
|
2945
|
+
border-radius: var(--s-br);
|
|
2946
|
+
background: var(--s-background);
|
|
2947
|
+
}
|
|
2948
|
+
|
|
2949
|
+
.campaignSourceTitle {
|
|
2950
|
+
display: flex;
|
|
2951
|
+
gap: 0.4rem;
|
|
2952
|
+
align-items: center;
|
|
2953
|
+
margin: 0;
|
|
2954
|
+
color: var(--s-paragraph);
|
|
2955
|
+
font-size: 0.92rem;
|
|
2956
|
+
font-weight: 700;
|
|
2957
|
+
|
|
2958
|
+
svg {
|
|
2959
|
+
color: var(--s-primary);
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
|
|
2963
|
+
.campaignDrop {
|
|
2964
|
+
@include sms-focus;
|
|
2965
|
+
|
|
2966
|
+
display: flex;
|
|
2967
|
+
flex-direction: column;
|
|
2968
|
+
gap: 0.5rem;
|
|
2969
|
+
align-items: center;
|
|
2970
|
+
justify-content: center;
|
|
2971
|
+
box-sizing: border-box;
|
|
2972
|
+
min-height: 120px;
|
|
2973
|
+
padding: 1rem;
|
|
2974
|
+
border: 1px dashed var(--s-line);
|
|
2975
|
+
border-radius: var(--s-br);
|
|
2976
|
+
background: var(--s-surface);
|
|
2977
|
+
color: var(--s-muted);
|
|
2978
|
+
text-align: center;
|
|
2979
|
+
cursor: pointer;
|
|
2980
|
+
|
|
2981
|
+
p {
|
|
2982
|
+
max-width: 34ch;
|
|
2983
|
+
text-align: center;
|
|
2984
|
+
}
|
|
2985
|
+
|
|
2986
|
+
&:hover {
|
|
2987
|
+
border-color: var(--s-primary);
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
|
|
2991
|
+
.campaignDropOn {
|
|
2992
|
+
border-color: var(--s-primary);
|
|
2993
|
+
background: var(--s-tint);
|
|
2994
|
+
color: var(--s-primary);
|
|
2995
|
+
}
|
|
2996
|
+
|
|
2997
|
+
// Two selects and the button that takes the rows, on one line where there is
|
|
2998
|
+
// room. The button's own width is its label, which grows with the count.
|
|
2999
|
+
.campaignColumns {
|
|
3000
|
+
display: flex;
|
|
3001
|
+
flex-wrap: wrap;
|
|
3002
|
+
gap: 0.6rem;
|
|
3003
|
+
align-items: flex-end;
|
|
3004
|
+
|
|
3005
|
+
> .field {
|
|
3006
|
+
flex: 1 1 140px;
|
|
3007
|
+
min-width: 0;
|
|
3008
|
+
}
|
|
3009
|
+
|
|
3010
|
+
> .help {
|
|
3011
|
+
flex: 1 1 100%;
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
3014
|
+
|
|
3015
|
+
.campaignCount {
|
|
3016
|
+
color: var(--s-paragraph);
|
|
3017
|
+
font-size: 0.88rem;
|
|
3018
|
+
|
|
3019
|
+
strong {
|
|
3020
|
+
font-weight: 700;
|
|
3021
|
+
}
|
|
3022
|
+
}
|
|
3023
|
+
|
|
3024
|
+
/* -------------------------------------------------------------- compose */
|
|
3025
|
+
|
|
3026
|
+
// The message on the left, what it becomes on the right. Side by side rather
|
|
3027
|
+
// than stacked because the point of the preview is watching it change as the
|
|
3028
|
+
// message is typed, and a panel below the fold is a panel nobody sees move.
|
|
3029
|
+
.campaignCompose {
|
|
3030
|
+
display: grid;
|
|
3031
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
|
|
3032
|
+
gap: 1rem;
|
|
3033
|
+
align-items: start;
|
|
3034
|
+
}
|
|
3035
|
+
|
|
3036
|
+
.campaignComposeMain {
|
|
3037
|
+
display: flex;
|
|
3038
|
+
flex-direction: column;
|
|
3039
|
+
gap: 0.85rem;
|
|
3040
|
+
min-width: 0;
|
|
3041
|
+
}
|
|
3042
|
+
|
|
3043
|
+
.campaignPreview {
|
|
3044
|
+
display: flex;
|
|
3045
|
+
flex-direction: column;
|
|
3046
|
+
gap: 0.6rem;
|
|
3047
|
+
box-sizing: border-box;
|
|
3048
|
+
padding: 0.85rem 1rem;
|
|
3049
|
+
border: 1px solid var(--s-line);
|
|
3050
|
+
border-radius: var(--s-br);
|
|
3051
|
+
background: var(--s-surface);
|
|
3052
|
+
}
|
|
3053
|
+
|
|
3054
|
+
.campaignPreviewList {
|
|
3055
|
+
display: flex;
|
|
3056
|
+
flex-direction: column;
|
|
3057
|
+
gap: 0.6rem;
|
|
3058
|
+
margin: 0;
|
|
3059
|
+
padding: 0;
|
|
3060
|
+
list-style: none;
|
|
3061
|
+
}
|
|
3062
|
+
|
|
3063
|
+
.campaignPreviewItem {
|
|
3064
|
+
display: flex;
|
|
3065
|
+
flex-direction: column;
|
|
3066
|
+
gap: 0.35rem;
|
|
3067
|
+
box-sizing: border-box;
|
|
3068
|
+
padding: 0.6rem 0.7rem;
|
|
3069
|
+
border: 1px solid var(--s-line);
|
|
3070
|
+
border-radius: var(--s-br);
|
|
3071
|
+
background: var(--s-background);
|
|
3072
|
+
}
|
|
3073
|
+
|
|
3074
|
+
.campaignPreviewWho {
|
|
3075
|
+
display: flex;
|
|
3076
|
+
gap: 0.5rem;
|
|
3077
|
+
align-items: center;
|
|
3078
|
+
min-width: 0;
|
|
3079
|
+
|
|
3080
|
+
strong {
|
|
3081
|
+
display: block;
|
|
3082
|
+
overflow: hidden;
|
|
3083
|
+
color: var(--s-paragraph);
|
|
3084
|
+
font-size: 0.84rem;
|
|
3085
|
+
font-weight: 700;
|
|
3086
|
+
text-overflow: ellipsis;
|
|
3087
|
+
white-space: nowrap;
|
|
3088
|
+
}
|
|
3089
|
+
|
|
3090
|
+
small {
|
|
3091
|
+
color: var(--s-muted);
|
|
3092
|
+
font-size: 0.74rem;
|
|
3093
|
+
font-variant-numeric: tabular-nums;
|
|
3094
|
+
}
|
|
3095
|
+
}
|
|
3096
|
+
|
|
3097
|
+
// The rendered message. `pre-wrap` because a campaign body carries the line
|
|
3098
|
+
// breaks somebody typed, and a preview that folded them away would not be one.
|
|
3099
|
+
.campaignPreviewBody {
|
|
3100
|
+
margin: 0;
|
|
3101
|
+
color: var(--s-paragraph);
|
|
3102
|
+
font-size: 0.84rem;
|
|
3103
|
+
line-height: 1.5;
|
|
3104
|
+
white-space: pre-wrap;
|
|
3105
|
+
overflow-wrap: anywhere;
|
|
3106
|
+
}
|
|
3107
|
+
|
|
3108
|
+
.campaignFooter {
|
|
3109
|
+
color: var(--s-paragraph);
|
|
3110
|
+
font-style: italic;
|
|
3111
|
+
}
|
|
3112
|
+
|
|
3113
|
+
/* --------------------------------------------------------------- review */
|
|
3114
|
+
|
|
3115
|
+
.campaignReview,
|
|
3116
|
+
.campaignReport {
|
|
3117
|
+
display: flex;
|
|
3118
|
+
flex-direction: column;
|
|
3119
|
+
gap: 1rem;
|
|
3120
|
+
}
|
|
3121
|
+
|
|
3122
|
+
// The same card the settings status block is, and deliberately so: a row of
|
|
3123
|
+
// labelled figures is a row of labelled figures, and a second design for one
|
|
3124
|
+
// would be a second thing to keep in step.
|
|
3125
|
+
.campaignFacts {
|
|
3126
|
+
display: flex;
|
|
3127
|
+
flex-wrap: wrap;
|
|
3128
|
+
gap: 0.75rem 1.5rem;
|
|
3129
|
+
box-sizing: border-box;
|
|
3130
|
+
padding: 0.85rem 1rem;
|
|
3131
|
+
border: 1px solid var(--s-line);
|
|
3132
|
+
border-radius: var(--s-br);
|
|
3133
|
+
background: var(--s-surface);
|
|
3134
|
+
}
|
|
3135
|
+
|
|
3136
|
+
// The step's own buttons, always at the foot of it, always right-aligned —
|
|
3137
|
+
// Back on the left of the pair because that is the order they are read in.
|
|
3138
|
+
.campaignFoot {
|
|
3139
|
+
display: flex;
|
|
3140
|
+
gap: 0.6rem;
|
|
3141
|
+
align-items: center;
|
|
3142
|
+
justify-content: flex-end;
|
|
3143
|
+
padding-top: 0.75rem;
|
|
3144
|
+
border-top: 1px solid var(--s-line);
|
|
3145
|
+
}
|
|
3146
|
+
|
|
3147
|
+
/* --------------------------------------------------------------- detail */
|
|
3148
|
+
|
|
3149
|
+
.campaignHeading {
|
|
3150
|
+
display: flex;
|
|
3151
|
+
flex-direction: column;
|
|
3152
|
+
gap: 0.2rem;
|
|
3153
|
+
min-width: 0;
|
|
3154
|
+
}
|
|
3155
|
+
|
|
3156
|
+
// The message, folded. `details` rather than a button and a piece of state:
|
|
3157
|
+
// the browser owns the open/closed, it is keyboard operable for nothing, and
|
|
3158
|
+
// the summary is a real heading when it is printed.
|
|
3159
|
+
.campaignFold {
|
|
3160
|
+
box-sizing: border-box;
|
|
3161
|
+
padding: 0.6rem 0.85rem;
|
|
3162
|
+
border: 1px solid var(--s-line);
|
|
3163
|
+
border-radius: var(--s-br);
|
|
3164
|
+
background: var(--s-surface);
|
|
3165
|
+
font-size: 0.84rem;
|
|
3166
|
+
|
|
3167
|
+
> summary {
|
|
3168
|
+
color: var(--s-paragraph);
|
|
3169
|
+
font-weight: 600;
|
|
3170
|
+
cursor: pointer;
|
|
3171
|
+
}
|
|
3172
|
+
}
|
|
3173
|
+
|
|
3174
|
+
.campaignFoldBody {
|
|
3175
|
+
margin: 0.6rem 0 0;
|
|
3176
|
+
color: var(--s-paragraph);
|
|
3177
|
+
line-height: 1.5;
|
|
3178
|
+
white-space: pre-wrap;
|
|
3179
|
+
overflow-wrap: anywhere;
|
|
3180
|
+
}
|
|
3181
|
+
|
|
3182
|
+
.campaignPager {
|
|
3183
|
+
display: flex;
|
|
3184
|
+
gap: 0.75rem;
|
|
3185
|
+
align-items: center;
|
|
3186
|
+
justify-content: flex-end;
|
|
3187
|
+
}
|
|
3188
|
+
|
|
3189
|
+
/* ------------------------------------------------------------- opt-outs */
|
|
3190
|
+
|
|
3191
|
+
// Number, note, and the button, on one row. The note is given the slack
|
|
3192
|
+
// because "asked to stop, 4 September" is the part somebody actually types.
|
|
3193
|
+
.optOutAdd {
|
|
3194
|
+
display: flex;
|
|
3195
|
+
flex-wrap: wrap;
|
|
3196
|
+
gap: 0.6rem;
|
|
3197
|
+
align-items: flex-end;
|
|
3198
|
+
box-sizing: border-box;
|
|
3199
|
+
padding: 0.75rem 0.85rem;
|
|
3200
|
+
border: 1px solid var(--s-line);
|
|
3201
|
+
border-radius: var(--s-br);
|
|
3202
|
+
background: var(--s-surface);
|
|
3203
|
+
|
|
3204
|
+
> .field:first-child {
|
|
3205
|
+
flex: 0 1 12rem;
|
|
3206
|
+
}
|
|
3207
|
+
|
|
3208
|
+
> .field {
|
|
3209
|
+
flex: 1 1 14rem;
|
|
3210
|
+
min-width: 0;
|
|
3211
|
+
}
|
|
3212
|
+
}
|
|
3213
|
+
|
|
3214
|
+
@media (max-width: 900px) {
|
|
3215
|
+
// The preview stops being a column and becomes a panel under the message.
|
|
3216
|
+
// Below this width the two side by side leave the textarea about forty
|
|
3217
|
+
// characters wide, which is narrower than the message being written in it.
|
|
3218
|
+
.campaignCompose {
|
|
3219
|
+
grid-template-columns: minmax(0, 1fr);
|
|
3220
|
+
}
|
|
3221
|
+
|
|
3222
|
+
.campaignFoot {
|
|
3223
|
+
flex-wrap: wrap;
|
|
3224
|
+
}
|
|
3225
|
+
|
|
3226
|
+
.campaignPager {
|
|
3227
|
+
justify-content: space-between;
|
|
3228
|
+
}
|
|
3229
|
+
}
|