@miliastry/quasar 1.1.0 → 1.2.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 +1 -1
- package/dist/Visuals/lyne.css +257 -3
- package/dist/Visuals/osu.css +357 -6
- package/dist/index.js +850 -98
- package/dist/index.mjs +846 -99
- package/dist/types/BBCode/BBCodeDocumentModel.d.ts +11 -1
- package/dist/types/Visitors/DOMMorpher.d.ts +6 -0
- package/dist/types/Visitors/HTMLRenderer.d.ts +120 -8
- package/dist/types/Visitors/index.d.ts +1 -1
- package/dist/types/Visuals/BoxDrawer.d.ts +10 -5
- package/dist/types/Visuals/LyneAudio.d.ts +8 -0
- package/dist/types/Visuals/index.d.ts +1 -0
- package/dist/types/index.d.ts +4 -3
- package/package.json +1 -1
- package/src/BBCode/BBCodeDocumentModel.ts +36 -1
- package/src/HTML/HTMLToGreenNode.ts +8 -0
- package/src/Semantic/SemanticAnalyzer.ts +43 -0
- package/src/Visitors/BBCodeExporter.ts +51 -5
- package/src/Visitors/BlockPatcher.ts +36 -11
- package/src/Visitors/DOMMorpher.ts +44 -38
- package/src/Visitors/HTMLRenderer.ts +402 -59
- package/src/Visitors/index.ts +1 -1
- package/src/Visuals/BoxDrawer.ts +56 -10
- package/src/Visuals/LyneAudio.ts +346 -0
- package/src/Visuals/index.ts +1 -0
- package/src/Visuals/lyne.css +257 -3
- package/src/Visuals/osu.css +357 -6
- package/src/index.ts +6 -3
package/README.md
CHANGED
|
@@ -42,4 +42,4 @@ Quasar's internal architecture is highly advanced. If you want to understand how
|
|
|
42
42
|
|
|
43
43
|
[**Miliastry Source License (MSL-1.0)**](LICENSE) — Copyright (c) 2026 hxovc / Miliastry Team.
|
|
44
44
|
|
|
45
|
-
Quasar is Source-Available under a custom license designed to protect the Miliastry ecosystem. You can use, modify, and distribute the engine for any project—including standard visual BBCode editors or osu! profile tools—**except** for creating a Competing Product (i.e., a direct clone of Miliastry Nova as an integrated IDE, or a competing standalone engine based on this code).
|
|
45
|
+
Quasar is Source-Available under a custom license designed to protect the Miliastry ecosystem. You can use, modify, and distribute the engine for any project—including standard visual BBCode editors or osu! profile tools—**except** for creating a Competing Product (i.e., a direct clone of Miliastry Nova as an integrated IDE, or a competing standalone engine based on this code).
|
package/dist/Visuals/lyne.css
CHANGED
|
@@ -31,10 +31,17 @@
|
|
|
31
31
|
--color-accent: #2EE6E2;
|
|
32
32
|
--color-accent-bright: #68FFF8;
|
|
33
33
|
--color-warning: #FFC34D;
|
|
34
|
+
--color-danger: #FF3B5C;
|
|
34
35
|
--color-text-primary: #FFFFFF;
|
|
35
36
|
--color-text-mid: #9EACD4;
|
|
36
37
|
--color-text-dim: #606C8F;
|
|
37
38
|
--color-hairline: rgba(255, 255, 255, 0.12);
|
|
39
|
+
--color-hairline-bright: rgba(142, 155, 196, 0.35);
|
|
40
|
+
--color-surface: #0B1024;
|
|
41
|
+
--color-surface-bright: #141C3C;
|
|
42
|
+
--color-inset-well: #080D20;
|
|
43
|
+
--color-on-accent: #05060F;
|
|
44
|
+
--cut-control: 10px;
|
|
38
45
|
--font-display: var(--font-syne-display, "Saira Condensed"), "Saira Condensed", sans-serif;
|
|
39
46
|
--font-body: var(--font-syne-body, "Saira"), "Saira", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
40
47
|
--font-numeric: var(--font-syne-mono, "IBM Plex Mono"), "IBM Plex Mono", monospace;
|
|
@@ -914,9 +921,256 @@
|
|
|
914
921
|
margin: 4px 0 !important;
|
|
915
922
|
}
|
|
916
923
|
|
|
917
|
-
/* Audio:
|
|
918
|
-
.
|
|
919
|
-
|
|
924
|
+
/* ─── Audio: LINE chrome redesign (spec docs/design-spec/bbcode-audio-player) ── */
|
|
925
|
+
.bbcode-preview-lyne .lx-audio,
|
|
926
|
+
.bbcode-preview.theme-lyne .lx-audio,
|
|
927
|
+
[data-theme='syne'] .lx-audio,
|
|
928
|
+
[data-dialect='lyne'] .lx-audio,
|
|
929
|
+
.lx-audio {
|
|
930
|
+
--c: var(--cut-control, 10px);
|
|
931
|
+
display: inline-block !important;
|
|
932
|
+
width: 100% !important;
|
|
933
|
+
max-width: 560px !important;
|
|
934
|
+
margin: 14px 0 !important;
|
|
935
|
+
background:
|
|
936
|
+
linear-gradient(180deg, var(--color-surface-bright, #141C3C) 0%, var(--color-surface, #0B1024) 38%, var(--color-inset-well, #080D20) 100%) !important;
|
|
937
|
+
border: 1px solid var(--color-hairline-bright, rgba(142, 155, 196, 0.35)) !important;
|
|
938
|
+
clip-path: polygon(var(--c) 0, 100% 0, 100% calc(100% - var(--c)), calc(100% - var(--c)) 100%, 0 100%, 0 var(--c)) !important;
|
|
939
|
+
position: relative;
|
|
940
|
+
font-family: var(--font-body, "Saira", sans-serif);
|
|
941
|
+
transition: border-color 120ms cubic-bezier(0.16, 1.0, 0.3, 1.0);
|
|
942
|
+
text-align: left;
|
|
943
|
+
box-sizing: border-box;
|
|
944
|
+
vertical-align: middle;
|
|
945
|
+
}
|
|
946
|
+
.lx-audio audio {
|
|
947
|
+
position: absolute !important;
|
|
948
|
+
width: 1px !important;
|
|
949
|
+
height: 1px !important;
|
|
950
|
+
opacity: 0 !important;
|
|
951
|
+
pointer-events: none !important;
|
|
952
|
+
clip: rect(0, 0, 0, 0) !important;
|
|
953
|
+
}
|
|
954
|
+
.lx-audio:hover {
|
|
955
|
+
border-color: rgba(46, 230, 226, 0.45) !important;
|
|
956
|
+
}
|
|
957
|
+
.lx-audio.is-playing {
|
|
958
|
+
border-color: rgba(46, 230, 226, 0.6) !important;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
/* thin accent baseline — the "catch line" motif; fills with progress */
|
|
962
|
+
.lx-audio .lx-track {
|
|
963
|
+
position: relative;
|
|
964
|
+
height: 12px;
|
|
965
|
+
cursor: pointer;
|
|
966
|
+
background:
|
|
967
|
+
repeating-linear-gradient(-45deg, rgba(142,155,196,0.10) 0 2px, transparent 2px 9px),
|
|
968
|
+
var(--color-inset-well, #080D20);
|
|
969
|
+
}
|
|
970
|
+
.lx-audio .lx-track .fill {
|
|
971
|
+
position: absolute;
|
|
972
|
+
inset: 0 auto 0 0;
|
|
973
|
+
width: 0%;
|
|
974
|
+
background: linear-gradient(90deg, rgba(46,230,226,0.10), rgba(46,230,226,0.22));
|
|
975
|
+
border-right: 2px solid var(--color-accent, #2EE6E2);
|
|
976
|
+
box-shadow: 0 0 12px rgba(46, 230, 226, 0.55);
|
|
977
|
+
}
|
|
978
|
+
.lx-audio .lx-row {
|
|
979
|
+
display: flex;
|
|
980
|
+
align-items: center;
|
|
981
|
+
gap: 14px;
|
|
982
|
+
padding: 10px 16px 12px;
|
|
983
|
+
}
|
|
984
|
+
.lx-audio .lx-btn {
|
|
985
|
+
flex: none;
|
|
986
|
+
width: 40px;
|
|
987
|
+
height: 40px;
|
|
988
|
+
display: grid;
|
|
989
|
+
place-items: center;
|
|
990
|
+
background: var(--color-accent, #2EE6E2);
|
|
991
|
+
color: var(--color-on-accent, #05060F);
|
|
992
|
+
cursor: pointer;
|
|
993
|
+
border: none;
|
|
994
|
+
clip-path: polygon(var(--c) 0, 100% 0, 100% calc(100% - var(--c)), calc(100% - var(--c)) 100%, 0 100%, 0 var(--c));
|
|
995
|
+
transition: background 120ms cubic-bezier(0.16, 1.0, 0.3, 1.0), transform 120ms cubic-bezier(0.16, 1.0, 0.3, 1.0);
|
|
996
|
+
}
|
|
997
|
+
.lx-audio .lx-btn:hover {
|
|
998
|
+
background: var(--color-accent-bright, #7FF5F0);
|
|
999
|
+
}
|
|
1000
|
+
.lx-audio .lx-btn:active {
|
|
1001
|
+
transform: scale(0.94);
|
|
1002
|
+
}
|
|
1003
|
+
.lx-audio .lx-btn svg {
|
|
1004
|
+
width: 16px;
|
|
1005
|
+
height: 16px;
|
|
1006
|
+
fill: var(--color-on-accent, #05060F);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
.lx-audio .lx-title {
|
|
1010
|
+
flex: 1;
|
|
1011
|
+
min-width: 0;
|
|
1012
|
+
}
|
|
1013
|
+
.lx-audio .lx-title .name {
|
|
1014
|
+
font-family: var(--font-display, "Saira Condensed", sans-serif);
|
|
1015
|
+
font-weight: 600;
|
|
1016
|
+
font-size: 16px;
|
|
1017
|
+
text-transform: uppercase;
|
|
1018
|
+
letter-spacing: 1px;
|
|
1019
|
+
white-space: nowrap;
|
|
1020
|
+
overflow: hidden;
|
|
1021
|
+
text-overflow: ellipsis;
|
|
1022
|
+
color: var(--color-text-primary, #F2F5FF);
|
|
1023
|
+
}
|
|
1024
|
+
.lx-audio .lx-title .label {
|
|
1025
|
+
font-family: var(--font-numeric, "IBM Plex Mono", monospace);
|
|
1026
|
+
font-size: 10px;
|
|
1027
|
+
font-weight: 500;
|
|
1028
|
+
letter-spacing: 2px;
|
|
1029
|
+
text-transform: uppercase;
|
|
1030
|
+
color: var(--color-text-dim, #8E9BC4);
|
|
1031
|
+
display: flex;
|
|
1032
|
+
align-items: center;
|
|
1033
|
+
gap: 6px;
|
|
1034
|
+
margin-top: 1px;
|
|
1035
|
+
}
|
|
1036
|
+
.lx-audio .lx-title .label .dot {
|
|
1037
|
+
width: 5px;
|
|
1038
|
+
height: 5px;
|
|
1039
|
+
background: var(--color-text-dim, #8E9BC4);
|
|
1040
|
+
flex: none;
|
|
1041
|
+
transition: background 120ms;
|
|
1042
|
+
}
|
|
1043
|
+
.lx-audio.is-playing .lx-title .label .dot {
|
|
1044
|
+
background: var(--color-accent, #2EE6E2);
|
|
1045
|
+
box-shadow: 0 0 6px rgba(46,230,226,0.9);
|
|
1046
|
+
animation: lx-beat 606ms infinite;
|
|
1047
|
+
}
|
|
1048
|
+
@keyframes lx-beat {
|
|
1049
|
+
0% { transform: scale(1.25); }
|
|
1050
|
+
100% { transform: scale(1); }
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
.lx-audio .lx-vol {
|
|
1054
|
+
display: flex;
|
|
1055
|
+
align-items: center;
|
|
1056
|
+
gap: 6px;
|
|
1057
|
+
flex: none;
|
|
1058
|
+
}
|
|
1059
|
+
.lx-audio .lx-vol-btn {
|
|
1060
|
+
background: none;
|
|
1061
|
+
border: none;
|
|
1062
|
+
padding: 2px;
|
|
1063
|
+
cursor: pointer;
|
|
1064
|
+
display: grid;
|
|
1065
|
+
place-items: center;
|
|
1066
|
+
color: var(--color-text-dim, #8E9BC4);
|
|
1067
|
+
transition: color 120ms cubic-bezier(0.16, 1.0, 0.3, 1.0);
|
|
1068
|
+
}
|
|
1069
|
+
.lx-audio .lx-vol-btn:hover {
|
|
1070
|
+
color: var(--color-accent, #2EE6E2);
|
|
1071
|
+
}
|
|
1072
|
+
.lx-audio .lx-vol-btn svg {
|
|
1073
|
+
width: 14px;
|
|
1074
|
+
height: 14px;
|
|
1075
|
+
fill: currentColor;
|
|
1076
|
+
}
|
|
1077
|
+
.lx-audio .lx-vol-slider {
|
|
1078
|
+
-webkit-appearance: none;
|
|
1079
|
+
appearance: none;
|
|
1080
|
+
width: 56px;
|
|
1081
|
+
height: 4px;
|
|
1082
|
+
background: var(--color-inset-well, #080D20);
|
|
1083
|
+
border: 1px solid var(--color-hairline, rgba(142, 155, 196, 0.25));
|
|
1084
|
+
outline: none;
|
|
1085
|
+
cursor: pointer;
|
|
1086
|
+
border-radius: 0;
|
|
1087
|
+
vertical-align: middle;
|
|
1088
|
+
}
|
|
1089
|
+
.lx-audio .lx-vol-slider::-webkit-slider-thumb {
|
|
1090
|
+
-webkit-appearance: none;
|
|
1091
|
+
appearance: none;
|
|
1092
|
+
width: 8px;
|
|
1093
|
+
height: 12px;
|
|
1094
|
+
background: var(--color-accent, #2EE6E2);
|
|
1095
|
+
clip-path: polygon(2px 0, 100% 0, 100% calc(100% - 2px), calc(100% - 2px) 100%, 0 100%, 0 2px);
|
|
1096
|
+
cursor: pointer;
|
|
1097
|
+
transition: transform 120ms, background 120ms;
|
|
1098
|
+
}
|
|
1099
|
+
.lx-audio .lx-vol-slider::-moz-range-thumb {
|
|
1100
|
+
width: 8px;
|
|
1101
|
+
height: 12px;
|
|
1102
|
+
border: none;
|
|
1103
|
+
border-radius: 0;
|
|
1104
|
+
background: var(--color-accent, #2EE6E2);
|
|
1105
|
+
clip-path: polygon(2px 0, 100% 0, 100% calc(100% - 2px), calc(100% - 2px) 100%, 0 100%, 0 2px);
|
|
1106
|
+
cursor: pointer;
|
|
1107
|
+
}
|
|
1108
|
+
.lx-audio .lx-vol-slider:hover::-webkit-slider-thumb {
|
|
1109
|
+
background: var(--color-accent-bright, #7FF5F0);
|
|
1110
|
+
transform: scaleY(1.15);
|
|
1111
|
+
}
|
|
1112
|
+
.lx-audio .lx-vol-slider:hover::-moz-range-thumb {
|
|
1113
|
+
background: var(--color-accent-bright, #7FF5F0);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
.lx-audio .lx-time {
|
|
1117
|
+
flex: none;
|
|
1118
|
+
font-family: var(--font-numeric, "IBM Plex Mono", monospace);
|
|
1119
|
+
font-weight: 500;
|
|
1120
|
+
font-size: 12px;
|
|
1121
|
+
letter-spacing: 0.5px;
|
|
1122
|
+
color: var(--color-text-mid, #AAB6DE);
|
|
1123
|
+
font-variant-numeric: tabular-nums;
|
|
1124
|
+
}
|
|
1125
|
+
.lx-audio .lx-time .cur {
|
|
1126
|
+
color: var(--color-text-primary, #F2F5FF);
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
.lx-audio .lx-speed {
|
|
1130
|
+
flex: none;
|
|
1131
|
+
font-family: var(--font-numeric, "IBM Plex Mono", monospace);
|
|
1132
|
+
font-size: 11px;
|
|
1133
|
+
font-weight: 500;
|
|
1134
|
+
color: var(--color-text-dim, #8E9BC4);
|
|
1135
|
+
background: none;
|
|
1136
|
+
border: 1px solid var(--color-hairline, rgba(142, 155, 196, 0.18));
|
|
1137
|
+
padding: 3px 8px;
|
|
1138
|
+
cursor: pointer;
|
|
1139
|
+
letter-spacing: 1px;
|
|
1140
|
+
clip-path: polygon(5px 0, 100% 0, 100% calc(100% - 5px), calc(100% - 5px) 100%, 0 100%, 0 5px);
|
|
1141
|
+
transition: color 120ms, border-color 120ms;
|
|
1142
|
+
}
|
|
1143
|
+
.lx-audio .lx-speed:hover {
|
|
1144
|
+
color: var(--color-accent, #2EE6E2);
|
|
1145
|
+
border-color: rgba(46,230,226,0.4);
|
|
1146
|
+
}
|
|
1147
|
+
.lx-audio .lx-speed.active {
|
|
1148
|
+
color: var(--color-accent, #2EE6E2);
|
|
1149
|
+
border-color: rgba(46,230,226,0.5);
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
/* states */
|
|
1153
|
+
.lx-audio.is-loading .lx-btn svg {
|
|
1154
|
+
opacity: 0.3;
|
|
1155
|
+
}
|
|
1156
|
+
.lx-audio.is-loading .fill {
|
|
1157
|
+
border-right-color: var(--color-text-dim, #8E9BC4);
|
|
1158
|
+
box-shadow: none;
|
|
1159
|
+
}
|
|
1160
|
+
.lx-audio.is-error {
|
|
1161
|
+
border-color: rgba(255, 59, 92, 0.5) !important;
|
|
1162
|
+
}
|
|
1163
|
+
.lx-audio.is-error .fill {
|
|
1164
|
+
border-right-color: var(--color-danger, #FF3B5C);
|
|
1165
|
+
box-shadow: 0 0 12px rgba(255,59,92,0.5);
|
|
1166
|
+
}
|
|
1167
|
+
.lx-audio.is-error .lx-title .label {
|
|
1168
|
+
color: var(--color-danger, #FF3B5C);
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
/* Fallback si se usa audio nativo directo */
|
|
1172
|
+
audio.bb-audio {
|
|
1173
|
+
display: inline-block !important;
|
|
920
1174
|
width: 100% !important;
|
|
921
1175
|
max-width: 420px !important;
|
|
922
1176
|
margin: 10px 0 !important;
|
package/dist/Visuals/osu.css
CHANGED
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) blockquote {
|
|
74
74
|
padding: 0 0 0 20px;
|
|
75
75
|
margin: 0 0 20px 0;
|
|
76
|
-
border-left: 2px solid
|
|
76
|
+
border-left: 2px solid var(--osu-accent);
|
|
77
77
|
color: #ffffff;
|
|
78
78
|
font-style: normal;
|
|
79
79
|
background: none;
|
|
@@ -83,8 +83,8 @@
|
|
|
83
83
|
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) pre {
|
|
84
84
|
padding: 10px;
|
|
85
85
|
margin-bottom: 10px;
|
|
86
|
-
background:
|
|
87
|
-
border: 1px solid
|
|
86
|
+
background: var(--osu-code-bg);
|
|
87
|
+
border: 1px solid var(--osu-code-border);
|
|
88
88
|
border-radius: 8px;
|
|
89
89
|
overflow-x: auto;
|
|
90
90
|
}
|
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) details summary {
|
|
151
151
|
cursor: pointer;
|
|
152
152
|
font-weight: 600;
|
|
153
|
-
color:
|
|
153
|
+
color: var(--osu-accent);
|
|
154
154
|
font-size: 13px;
|
|
155
155
|
user-select: none;
|
|
156
156
|
}
|
|
@@ -176,7 +176,7 @@
|
|
|
176
176
|
display: list-item;
|
|
177
177
|
}
|
|
178
178
|
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) li::marker {
|
|
179
|
-
color:
|
|
179
|
+
color: var(--osu-accent);
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
/* ─── Media ──────────────────────────────────────────── */
|
|
@@ -195,7 +195,11 @@
|
|
|
195
195
|
border-radius: 8px;
|
|
196
196
|
}
|
|
197
197
|
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) audio {
|
|
198
|
+
/* inline-block: el preflight de Tailwind fuerza `audio{display:block}`
|
|
199
|
+
* y eso rompe el centrado por `text-align:center` de [centre]. */
|
|
200
|
+
display: inline-block;
|
|
198
201
|
width: 100%;
|
|
202
|
+
max-width: 420px;
|
|
199
203
|
}
|
|
200
204
|
|
|
201
205
|
/* ─── Image Map ──────────────────────────────────────── */
|
|
@@ -268,7 +272,106 @@
|
|
|
268
272
|
display: inline-block;
|
|
269
273
|
transform: rotate(-5deg) scale(0.95);
|
|
270
274
|
font-style: italic;
|
|
271
|
-
color:
|
|
275
|
+
color: var(--osu-bloom);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* ─── Semantic Spacing ───────────────────────────────── */
|
|
279
|
+
|
|
280
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .bbcode-sp {
|
|
281
|
+
display: block;
|
|
282
|
+
height: 0;
|
|
283
|
+
min-height: 0;
|
|
284
|
+
margin: 0;
|
|
285
|
+
padding: 0;
|
|
286
|
+
}
|
|
287
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .bbcode-para {
|
|
288
|
+
display: block;
|
|
289
|
+
height: 1em;
|
|
290
|
+
min-height: 12px;
|
|
291
|
+
padding: 0;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/* ─── Vocabulario de clases del dialecto osu ──────────────────────────────
|
|
295
|
+
*
|
|
296
|
+
* Con `dialect: 'osu'` el renderer emite los nombres de clase reales de osu!
|
|
297
|
+
* (`well`, `js-spoilerbox`, `imagemap__link`, …) en vez de los de Miliastry
|
|
298
|
+
* (`notice`, `imagemap-container`, …). Sobre osu.ppy.sh eso basta: su propia
|
|
299
|
+
* hoja los pinta. Fuera de ahí —el preview de la app, el HTML autónomo de
|
|
300
|
+
* `scripts/osu-inject.ts`— no hay nadie, y estas reglas son ese nadie.
|
|
301
|
+
*
|
|
302
|
+
* ── Un solo parámetro, como osu ──────────────────────────────────────
|
|
303
|
+
*
|
|
304
|
+
* osu! no hardcodea sus colores: define `--base-hue` y deriva todo con
|
|
305
|
+
* `hsl()`, porque el usuario elige el tono de su tema. Medirlos y copiar el
|
|
306
|
+
* resultado congelaría UN tema concreto. Así que aquí se reproduce la
|
|
307
|
+
* mecánica, no la foto: los pares saturación/luminosidad son fijos por rol
|
|
308
|
+
* (la familia `b` es fondo al 10%, la `l` enlaces al 40%) y el tono entra por
|
|
309
|
+
* variable.
|
|
310
|
+
*
|
|
311
|
+
* `var(--base-hue, 338)` consume el tono del documento cuando existe —en la
|
|
312
|
+
* página real de osu existe, y ahí gana el del usuario— y si no cae a 338.
|
|
313
|
+
*
|
|
314
|
+
* Ese respaldo NO es el tono de osu (253), y es deliberado: esta hoja se
|
|
315
|
+
* consume sobre todo DENTRO de Miliastry, cuyo modo osu tiene fondo rosado
|
|
316
|
+
* (`#2a1f23`, tono 338) y acento `--accent-pink` (~332). Cayendo al 253 se
|
|
317
|
+
* mezclaban morados de osu sobre un fondo rosa nuestro, que se veía «casi
|
|
318
|
+
* bien» y por eso no saltaba. Un host puede fijar `--base-hue` para forzar
|
|
319
|
+
* otro.
|
|
320
|
+
*
|
|
321
|
+
* Las reglas de arriba (`.notice`, `.imagemap-container`, `.imagemap-area`)
|
|
322
|
+
* siguen vivas: son los nombres que emiten los dialectos miliastry y lyne.
|
|
323
|
+
* Esta sección añade, no reemplaza.
|
|
324
|
+
*/
|
|
325
|
+
|
|
326
|
+
/* Qué sigue al tono y qué no: EL CONTENIDO SIGUE, LAS SEÑALES NO.
|
|
327
|
+
*
|
|
328
|
+
* Lo que el BBCode pinta —citas, listas, código, cajas, enlaces— se deriva de
|
|
329
|
+
* `--osu-hue`, porque su color no significa nada por sí mismo: es la piel del
|
|
330
|
+
* documento. Lo que comunica un estado conserva su color fijo, porque ahí el
|
|
331
|
+
* color ES el mensaje: el rojo de `.media-error`, el negro sobre negro de
|
|
332
|
+
* `.spoiler` (que en osu es literalmente eso), el rosa de selección de las
|
|
333
|
+
* áreas de imagemap —una ayuda de edición, no contenido— y el degradado
|
|
334
|
+
* deliberadamente multicolor de `.sparkle`. Los blancos y los `rgba()`
|
|
335
|
+
* neutros tampoco: son veladuras, no color.
|
|
336
|
+
*
|
|
337
|
+
* Si vienes a "terminar el trabajo" convirtiendo los que quedan, esto es el
|
|
338
|
+
* porqué de que sigan ahí.
|
|
339
|
+
*/
|
|
340
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) {
|
|
341
|
+
--osu-hue: var(--base-hue, 338);
|
|
342
|
+
--osu-bg-deep: hsl(var(--osu-hue), 10%, 15%); /* fondo hundido */
|
|
343
|
+
--osu-border: hsl(var(--osu-hue), 10%, 40%); /* borde sobre ese fondo */
|
|
344
|
+
--osu-link: hsl(var(--osu-hue), 40%, 75%); /* enlaces, perfiles, cajas */
|
|
345
|
+
--osu-link-hi: hsl(var(--osu-hue), 40%, 80%); /* el mismo, al pasar */
|
|
346
|
+
--osu-text: hsl(var(--osu-hue), 40%, 100%); /* texto sobre fondo hundido */
|
|
347
|
+
|
|
348
|
+
/* ── La escalera real de osu ──────────────────────────────────────────
|
|
349
|
+
* Leída de su página en vivo (`--hsl-*` sobre `.bbcode`), no deducida:
|
|
350
|
+
* osu define --base-hue y estos pares de saturación/luminosidad, y su
|
|
351
|
+
* `bbcode.less` asigna un rol a cada elemento. Los cinco alias de arriba
|
|
352
|
+
* son estos mismos: bg-deep = b5, border = b1, link = l2, link-hi = l1,
|
|
353
|
+
* text = c1. Se nombran los roles aparte para poder citar la hoja de osu
|
|
354
|
+
* por su nombre cuando se ajusta un elemento concreto. */
|
|
355
|
+
--osu-b1: hsl(var(--osu-hue), 10%, 40%);
|
|
356
|
+
--osu-b5: hsl(var(--osu-hue), 10%, 15%);
|
|
357
|
+
--osu-b6: hsl(var(--osu-hue), 10%, 10%);
|
|
358
|
+
--osu-c2: hsl(var(--osu-hue), 40%, 90%);
|
|
359
|
+
--osu-l1: hsl(var(--osu-hue), 40%, 80%);
|
|
360
|
+
--osu-l3: hsl(var(--osu-hue), 40%, 70%);
|
|
361
|
+
|
|
362
|
+
/* El acento del cuerpo en el look de MILIASTRY: filo de las citas,
|
|
363
|
+
* marcador de lista, título de `details`. Era el literal `#D194B3`, que es
|
|
364
|
+
* exactamente hsl(330,40%,70%) — o sea `l3`. osu usa otros roles en esos
|
|
365
|
+
* mismos elementos; ver el bloque `[data-dialect="osu"]` más abajo. */
|
|
366
|
+
--osu-accent: var(--osu-l3);
|
|
367
|
+
/* Superficie del bloque de código y su filo, look de Miliastry. Eran
|
|
368
|
+
* `#1C1719` —hsl(336,10%,10%), que es `b6`— y `#43383A`. Este último
|
|
369
|
+
* estaba en el tono 349, fuera de la familia; al derivarlo se corrige. */
|
|
370
|
+
--osu-code-bg: var(--osu-b6);
|
|
371
|
+
--osu-code-border: hsl(var(--osu-hue), 9%, 24%);
|
|
372
|
+
/* Adorno `.flower`: era `#F0A0C0`, hsl(336,73%,78%). Es de Miliastry, osu
|
|
373
|
+
* no tiene nada parecido. */
|
|
374
|
+
--osu-bloom: hsl(var(--osu-hue), 73%, 78%);
|
|
272
375
|
}
|
|
273
376
|
|
|
274
377
|
/* ─── Semantic Spacing ───────────────────────────────── */
|
|
@@ -286,3 +389,251 @@
|
|
|
286
389
|
min-height: 12px;
|
|
287
390
|
padding: 0;
|
|
288
391
|
}
|
|
392
|
+
|
|
393
|
+
/* ─── Vocabulario de clases del dialecto osu ──────────────────────────────
|
|
394
|
+
*
|
|
395
|
+
* Con `dialect: 'osu'` el renderer emite los nombres de clase reales de osu!
|
|
396
|
+
* (`well`, `js-spoilerbox`, `imagemap__link`, …) en vez de los de Miliastry
|
|
397
|
+
* (`notice`, `imagemap-container`, …). Sobre osu.ppy.sh eso basta: su propia
|
|
398
|
+
* hoja los pinta. Fuera de ahí —el preview de la app, el HTML autónomo de
|
|
399
|
+
* `scripts/osu-inject.ts`— no hay nadie, y estas reglas son ese nadie.
|
|
400
|
+
*
|
|
401
|
+
* ── Un solo parámetro, como osu ──────────────────────────────────────
|
|
402
|
+
*
|
|
403
|
+
* osu! no hardcodea sus colores: define `--base-hue` y deriva todo con
|
|
404
|
+
* `hsl()`, porque el usuario elige el tono de su tema. Medirlos y copiar el
|
|
405
|
+
* resultado congelaría UN tema concreto. Así que aquí se reproduce la
|
|
406
|
+
* mecánica, no la foto: los pares saturación/luminosidad son fijos por rol
|
|
407
|
+
* (la familia `b` es fondo al 10%, la `l` enlaces al 40%) y el tono entra por
|
|
408
|
+
* variable.
|
|
409
|
+
*
|
|
410
|
+
* `var(--base-hue, 338)` consume el tono del documento cuando existe —en la
|
|
411
|
+
* página real de osu existe, y ahí gana el del usuario— y si no cae a 338.
|
|
412
|
+
*
|
|
413
|
+
* Ese respaldo NO es el tono de osu (253), y es deliberado: esta hoja se
|
|
414
|
+
* consume sobre todo DENTRO de Miliastry, cuyo modo osu tiene fondo rosado
|
|
415
|
+
* (`#2a1f23`, tono 338) y acento `--accent-pink` (~332). Cayendo al 253 se
|
|
416
|
+
* mezclaban morados de osu sobre un fondo rosa nuestro, que se veía «casi
|
|
417
|
+
* bien» y por eso no saltaba. Un host puede fijar `--base-hue` para forzar
|
|
418
|
+
* otro.
|
|
419
|
+
*
|
|
420
|
+
* Las reglas de arriba (`.notice`, `.imagemap-container`, `.imagemap-area`)
|
|
421
|
+
* siguen vivas: son los nombres que emiten los dialectos miliastry y lyne.
|
|
422
|
+
* Esta sección añade, no reemplaza.
|
|
423
|
+
*/
|
|
424
|
+
|
|
425
|
+
/* Qué sigue al tono y qué no: EL CONTENIDO SIGUE, LAS SEÑALES NO.
|
|
426
|
+
*
|
|
427
|
+
* Lo que el BBCode pinta —citas, listas, código, cajas, enlaces— se deriva de
|
|
428
|
+
* `--osu-hue`, porque su color no significa nada por sí mismo: es la piel del
|
|
429
|
+
* documento. Lo que comunica un estado conserva su color fijo, porque ahí el
|
|
430
|
+
* color ES el mensaje: el rojo de `.media-error`, el negro sobre negro de
|
|
431
|
+
* `.spoiler` (que en osu es literalmente eso), el rosa de selección de las
|
|
432
|
+
* áreas de imagemap —una ayuda de edición, no contenido— y el degradado
|
|
433
|
+
* deliberadamente multicolor de `.sparkle`. Los blancos y los `rgba()`
|
|
434
|
+
* neutros tampoco: son veladuras, no color.
|
|
435
|
+
*
|
|
436
|
+
* Si vienes a "terminar el trabajo" convirtiendo los que quedan, esto es el
|
|
437
|
+
* porqué de que sigan ahí.
|
|
438
|
+
*/
|
|
439
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) {
|
|
440
|
+
--osu-hue: var(--base-hue, 338);
|
|
441
|
+
--osu-bg-deep: hsl(var(--osu-hue), 10%, 15%); /* fondo hundido */
|
|
442
|
+
--osu-border: hsl(var(--osu-hue), 10%, 40%); /* borde sobre ese fondo */
|
|
443
|
+
--osu-link: hsl(var(--osu-hue), 40%, 75%); /* enlaces, perfiles, cajas */
|
|
444
|
+
--osu-link-hi: hsl(var(--osu-hue), 40%, 80%); /* el mismo, al pasar */
|
|
445
|
+
--osu-text: hsl(var(--osu-hue), 40%, 100%); /* texto sobre fondo hundido */
|
|
446
|
+
|
|
447
|
+
/* El acento del cuerpo: filo de las citas, marcador de lista, título de
|
|
448
|
+
* `details`. Era el literal `#D194B3`, que es exactamente hsl(330,40%,70%). */
|
|
449
|
+
--osu-accent: hsl(var(--osu-hue), 40%, 70%);
|
|
450
|
+
/* Superficie del bloque de código y su filo. Eran `#1C1719` —hsl(336,10%,10%)—
|
|
451
|
+
* y `#43383A`. Este último estaba en el tono 349, fuera de la familia; al
|
|
452
|
+
* derivarlo del tono se corrige de paso. */
|
|
453
|
+
--osu-code-bg: hsl(var(--osu-hue), 10%, 10%);
|
|
454
|
+
--osu-code-border: hsl(var(--osu-hue), 9%, 24%);
|
|
455
|
+
/* Adorno `.flower`: era `#F0A0C0`, hsl(336,73%,78%). */
|
|
456
|
+
--osu-bloom: hsl(var(--osu-hue), 73%, 78%);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/* Los enlaces de osu son del mismo morado que los perfiles, no azules. El
|
|
460
|
+
* azul de la sección base es el look de Miliastry, así que sólo se pisa
|
|
461
|
+
* cuando el preview declara el dialecto osu. */
|
|
462
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne)[data-dialect="osu"] a { color: var(--osu-link); }
|
|
463
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne)[data-dialect="osu"] a:hover { color: var(--osu-link-hi); border-bottom-color: var(--osu-link-hi); }
|
|
464
|
+
|
|
465
|
+
/* ── Roles de osu para el cuerpo del documento ────────────────────────────
|
|
466
|
+
* Fuente: `resources/css/bbcode.less` de osu-web, cruzada con la escalera
|
|
467
|
+
* medida en su página. Estos elementos tienen en Miliastry el acento rosa
|
|
468
|
+
* (`--osu-accent`), que es el look de la casa; bajo el dialecto osu mandan
|
|
469
|
+
* los roles de osu, igual que ya pasa arriba con los enlaces.
|
|
470
|
+
*/
|
|
471
|
+
|
|
472
|
+
/* La cita no lleva acento: el texto Y la barra son `c2`, y la barra la pinta
|
|
473
|
+
* osu con un ::before de 2px redondeado. El borde izquierdo da el mismo
|
|
474
|
+
* resultado a esta anchura. */
|
|
475
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne)[data-dialect="osu"] blockquote {
|
|
476
|
+
color: var(--osu-c2);
|
|
477
|
+
border-left-color: var(--osu-c2);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/* El bloque de código es `b5` y NO lleva borde. El nuestro usaba `b6` con un
|
|
481
|
+
* filo, que es más oscuro y más marcado que el de osu. */
|
|
482
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne)[data-dialect="osu"] pre {
|
|
483
|
+
background: var(--osu-b5);
|
|
484
|
+
border: none;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/* El código en línea también es `b5`, plano: ni veladura blanca ni filo. */
|
|
488
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne)[data-dialect="osu"] code.inline {
|
|
489
|
+
background: var(--osu-b5);
|
|
490
|
+
border: none;
|
|
491
|
+
padding: 1px 4px;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/* `[heading]` no es blanco en osu, es `l1`. */
|
|
495
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne)[data-dialect="osu"] h2 {
|
|
496
|
+
color: var(--osu-l1);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/* osu no le da color al marcador de lista: hereda el del texto. El rosa es
|
|
500
|
+
* cosa nuestra. */
|
|
501
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne)[data-dialect="osu"] li::marker {
|
|
502
|
+
color: inherit;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/* El spoiler de osu es negro puro sobre negro puro, no un gris. */
|
|
506
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne)[data-dialect="osu"] .spoiler {
|
|
507
|
+
background: #000;
|
|
508
|
+
color: #000;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/* Notice — osu lo llama `well` */
|
|
512
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .well {
|
|
513
|
+
padding: 19px;
|
|
514
|
+
border: 2px solid var(--osu-border);
|
|
515
|
+
border-radius: 4px;
|
|
516
|
+
background: var(--osu-bg-deep);
|
|
517
|
+
color: var(--osu-text);
|
|
518
|
+
text-align: center;
|
|
519
|
+
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/* Spoilerbox — estructura div > a(icono + texto) + div(cuerpo) */
|
|
523
|
+
/* osu no le pone caja propia al contenedor: el `margin: 8px 0` que trae
|
|
524
|
+
* `features/BBCode/styles.css` para el look de Miliastry sumaba 16px por
|
|
525
|
+
* caja (19 en una userpage real). Se declara a cero en vez de confiar en
|
|
526
|
+
* la especificidad, que aquí sólo ganaba en `display`. */
|
|
527
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .bbcode-spoilerbox { display: block; margin: 0; padding: 0; }
|
|
528
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .bbcode-spoilerbox__link {
|
|
529
|
+
display: inline-flex;
|
|
530
|
+
align-items: center;
|
|
531
|
+
color: var(--osu-link);
|
|
532
|
+
font-weight: 700;
|
|
533
|
+
text-decoration: none;
|
|
534
|
+
cursor: pointer;
|
|
535
|
+
/* osu lo deja al 100%; `features/BBCode/styles.css` lo baja a 0.85em para el
|
|
536
|
+
* look de Miliastry. Bajo este dialecto manda el de osu. */
|
|
537
|
+
font-size: 1em;
|
|
538
|
+
line-height: inherit;
|
|
539
|
+
/* Un `inline-flex` se alinea sobre la línea base del texto, así que el
|
|
540
|
+
* navegador reserva hueco para los descendentes DEBAJO y la caja crece de
|
|
541
|
+
* 21px a 26px. osu no lo sufre porque su icono es un glifo de fuente, que
|
|
542
|
+
* aporta una línea base real; el nuestro es un triángulo CSS sin texto y la
|
|
543
|
+
* base se sintetiza desde el borde inferior. Alinear arriba elimina el
|
|
544
|
+
* hueco: el enlace es el único contenido de su línea, así que `top` no
|
|
545
|
+
* cambia nada más. Medido: 26px -> 21px, que es lo que mide en osu. */
|
|
546
|
+
vertical-align: top;
|
|
547
|
+
}
|
|
548
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .bbcode-spoilerbox__link:hover { color: var(--osu-link-hi); border-bottom: none; }
|
|
549
|
+
|
|
550
|
+
/* El icono de osu es un glifo de Font Awesome 5, que no distribuimos. Este es
|
|
551
|
+
* un triángulo CSS equivalente: apunta a la derecha cerrado y rota al abrir.
|
|
552
|
+
* osu cambia de glifo en vez de rotar; el efecto leído es el mismo. Hereda
|
|
553
|
+
* `currentColor`, así que sigue al tono sin declarar nada. */
|
|
554
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .bbcode-spoilerbox__link-icon {
|
|
555
|
+
display: block;
|
|
556
|
+
position: relative;
|
|
557
|
+
flex: none;
|
|
558
|
+
width: 20px;
|
|
559
|
+
height: 21px;
|
|
560
|
+
}
|
|
561
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .bbcode-spoilerbox__link-icon::before {
|
|
562
|
+
content: "";
|
|
563
|
+
position: absolute;
|
|
564
|
+
top: 50%;
|
|
565
|
+
left: 5px;
|
|
566
|
+
width: 0;
|
|
567
|
+
height: 0;
|
|
568
|
+
border-left: 5px solid currentColor;
|
|
569
|
+
border-top: 4px solid transparent;
|
|
570
|
+
border-bottom: 4px solid transparent;
|
|
571
|
+
transform: translateY(-50%);
|
|
572
|
+
transform-origin: 2px 50%;
|
|
573
|
+
transition: transform 0.12s ease;
|
|
574
|
+
}
|
|
575
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .js-spoilerbox--open .bbcode-spoilerbox__link-icon::before {
|
|
576
|
+
transform: translateY(-50%) rotate(90deg);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/* El cuerpo arranca oculto. Lo abre la clase `js-spoilerbox--open` en el
|
|
580
|
+
* CONTENEDOR, que pone `bindBoxDrawer`. */
|
|
581
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .bbcode-spoilerbox__body {
|
|
582
|
+
display: none;
|
|
583
|
+
margin: 10px 0 0;
|
|
584
|
+
padding: 0 0 0 20px;
|
|
585
|
+
}
|
|
586
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .js-spoilerbox--open > .bbcode-spoilerbox__body { display: block; }
|
|
587
|
+
|
|
588
|
+
/* Imagemap — el contenedor ancla; los enlaces van absolutos con el
|
|
589
|
+
* left/top/width/height en % que el renderer escribe en el style inline.
|
|
590
|
+
* Sin el `position: relative` los enlaces caen al flujo. */
|
|
591
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .imagemap {
|
|
592
|
+
display: inline-block;
|
|
593
|
+
position: relative;
|
|
594
|
+
max-width: max-content;
|
|
595
|
+
}
|
|
596
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .imagemap__image {
|
|
597
|
+
display: inline;
|
|
598
|
+
max-width: 100%;
|
|
599
|
+
vertical-align: middle;
|
|
600
|
+
}
|
|
601
|
+
/* Transparentes en reposo, como en osu. El realce al pasar por encima es
|
|
602
|
+
* nuestro: en un editor conviene ver dónde están las áreas, y no altera la
|
|
603
|
+
* apariencia estática. */
|
|
604
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .imagemap__link {
|
|
605
|
+
display: block;
|
|
606
|
+
position: absolute;
|
|
607
|
+
box-sizing: border-box;
|
|
608
|
+
border-radius: 4px;
|
|
609
|
+
text-decoration: none;
|
|
610
|
+
transition: background-color 0.08s linear, box-shadow 0.08s linear;
|
|
611
|
+
}
|
|
612
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .imagemap__link:hover {
|
|
613
|
+
background: hsl(var(--osu-hue), 40%, 75%, 0.22);
|
|
614
|
+
box-shadow: inset 0 0 0 1.5px var(--osu-link);
|
|
615
|
+
border-bottom: none;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/* Alineación */
|
|
619
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .bbcode__align-centre { display: block; text-align: center; }
|
|
620
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .bbcode__align-left { display: block; text-align: left; }
|
|
621
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .bbcode__align-right { display: block; text-align: right; }
|
|
622
|
+
|
|
623
|
+
/* Perfil */
|
|
624
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .user-name {
|
|
625
|
+
display: inline;
|
|
626
|
+
color: var(--osu-link);
|
|
627
|
+
font-weight: 700;
|
|
628
|
+
text-decoration: none;
|
|
629
|
+
}
|
|
630
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .user-name:hover { color: var(--osu-link-hi); border-bottom: none; }
|
|
631
|
+
|
|
632
|
+
/* YouTube */
|
|
633
|
+
.bbcode-preview:not(.bbcode-preview-lyne):not(.theme-lyne) .u-embed-wide--bbcode {
|
|
634
|
+
display: inline-block;
|
|
635
|
+
width: 100%;
|
|
636
|
+
max-width: 425px;
|
|
637
|
+
aspect-ratio: 16 / 9;
|
|
638
|
+
border: 0;
|
|
639
|
+
}
|