@roottale/cms-renderer-next 0.65.1 → 0.66.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.
@@ -5,7 +5,7 @@
5
5
  * 독립적인 `.rt-exposure*` 이름을 쓰며 공유 보조 클래스는 `.rt-*`로 구분한다.
6
6
  * 문서 선택자는 `:where()`로 명시도를 낮춘다(ADR-0023 §5.1 #10).
7
7
  * 노출 UI는 테마 변수와 해당 클래스 범위에서 고객 사이트가 조정할 수 있다.
8
- * `!important`는 사용자의 동작 줄이기 설정을 보장하는 규칙에만 사용한다.
8
+ * `!important`는 동작 줄이기 설정과 모바일의 저장된 인라인 글자 크기·행간 보정에 한정한다.
9
9
  *
10
10
  * Token contract (zero-dependency):
11
11
  * Every `--rt-*` variable referenced below has a static fallback. The
@@ -14,6 +14,15 @@
14
14
  * element — `:where()` lets a plain class override.
15
15
  */
16
16
 
17
+ /* SIL OFL Pretendard. --rt-font-body 지정 시 고객 글꼴을 우선한다. */
18
+ @font-face {
19
+ font-family: "Pretendard Variable";
20
+ src: url('./fonts/PretendardVariable.woff2') format('woff2');
21
+ font-weight: 45 920;
22
+ font-style: normal;
23
+ font-display: swap;
24
+ }
25
+
17
26
  [data-roottale-cms] :where(.rt-cms-list) {
18
27
  display: grid;
19
28
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
@@ -486,14 +495,16 @@
486
495
  [data-roottale-cms] :where(.rt-cms-layout--toc-side) {
487
496
  grid-template-columns: minmax(0, 1fr) 15rem;
488
497
  align-items: start;
489
- max-inline-size: calc(var(--rt-cms-measure, 42.5rem) + 15rem + var(--rt-spacing-6, 1.5rem));
498
+ max-inline-size: calc(var(--rt-cms-measure, 45rem) + 15rem + var(--rt-spacing-6, 1.5rem));
490
499
  margin-inline: auto;
491
500
  }
492
501
  [data-roottale-cms] :where(.rt-cms-layout--toc-side .rt-cms-toc-side) {
493
502
  order: 0; /* 넓은 화면: 오른쪽 컬럼 */
494
503
  position: sticky;
495
- top: var(--rt-spacing-4, 1rem);
496
- max-block-size: calc(100vh - 2rem);
504
+ top: var(--rt-cms-scroll-offset, 5rem);
505
+ align-self: start;
506
+ max-block-size: calc(100dvh - var(--rt-cms-scroll-offset, 5rem) - 1rem);
507
+ overscroll-behavior: contain;
497
508
  overflow-y: auto;
498
509
  }
499
510
  /* 사이드바 목차는 컬럼 폭(15rem)에 맞춤 — 본문 measure cap 무시. */
@@ -503,23 +514,6 @@
503
514
  }
504
515
  }
505
516
 
506
- [data-roottale-cms] :where(.rt-cms-body),
507
- [data-roottale-cms] :where([data-roottale-cms="body"]) {
508
- min-inline-size: 0;
509
- font-family: var(--rt-font-body, system-ui, sans-serif);
510
- /* 읽기 표면 전용 스케일 — 네이버 프리미엄콘텐츠 기준 18px 기본, 테마 base 에
511
- 비례(테마가 base 를 키우면 본문도 같이 커진다). */
512
- font-size: var(--rt-cms-body-size, calc(var(--rt-font-size-base, 1rem) * 1.125));
513
- line-height: 1.8;
514
- letter-spacing: -0.01em; /* 한글 본문 대활자 자간 보정 */
515
- color: var(--rt-color-foreground, #06162f);
516
- /* 한글 조판 — 어절 단위 줄바꿈. 긴 URL·토큰만 anywhere 로 넘침 방지.
517
- 에디터(admin globals .tiptap-content)와 1:1 파리티. astro 는 rt-cms-body
518
- class 없이 data-roottale-cms="body" 만 쓰므로 attribute 셀렉터도 함께. */
519
- word-break: keep-all;
520
- overflow-wrap: anywhere;
521
- }
522
-
523
517
  /* 외부 게시판 HTML 가져오기. 원문의 안전한 inline style은 유지하되,
524
518
  넓은 표·이미지가 본문 measure 밖으로 페이지를 밀지 않게 경계를 둔다. */
525
519
  [data-roottale-cms] :where(.rt-imported-html) {
@@ -534,7 +528,7 @@
534
528
 
535
529
  /* 시각 브레드크럼 (avcd 구조, opt-in — RootTaleBlogPost `breadcrumb` prop). */
536
530
  [data-roottale-cms] :where(.rt-cms-breadcrumb) {
537
- max-inline-size: var(--rt-cms-measure, 42.5rem);
531
+ max-inline-size: var(--rt-cms-measure, 45rem);
538
532
  margin-inline: auto;
539
533
  margin-block-end: 1rem;
540
534
  font-family: var(--rt-font-body, system-ui, sans-serif);
@@ -581,10 +575,10 @@
581
575
 
582
576
  /* 네이버 프리미엄콘텐츠 류 크롬리스 헤더 — 장식 카드 대신 타이포+헤어라인. */
583
577
  [data-roottale-cms] :where(.rt-cms-post-header) {
584
- max-inline-size: var(--rt-cms-measure, 42.5rem);
578
+ max-inline-size: var(--rt-cms-measure, 45rem);
585
579
  margin-inline: auto;
586
580
  margin-block-end: var(--rt-spacing-7, 2rem);
587
- padding-block-end: var(--rt-spacing-5, 1.25rem);
581
+ padding-block-end: 42px;
588
582
  border-block-end: 1px solid color-mix(in srgb, var(--rt-color-border, #dceef3) 72%, transparent);
589
583
  }
590
584
 
@@ -610,13 +604,15 @@
610
604
  }
611
605
 
612
606
  [data-roottale-cms] :where(.rt-cms-post-header .rt-cms-title) {
613
- font-size: clamp(1.75rem, 1.35rem + 1.9vw, 2.375rem);
614
- font-weight: var(--rt-font-weight-bold, 800);
607
+ font-family: var(--rt-font-display, var(--rt-font-body, "Pretendard Variable", Pretendard, sans-serif));
608
+ font-size: 44px;
609
+ font-weight: var(--rt-font-weight-bold, 700);
615
610
  line-height: 1.3;
616
- margin-block-end: var(--rt-spacing-3, 0.75rem);
611
+ letter-spacing: -0.03em;
612
+ margin-block-end: 12px;
617
613
  word-break: keep-all;
618
614
  overflow-wrap: anywhere;
619
- text-wrap: balance;
615
+ text-wrap: wrap;
620
616
  }
621
617
 
622
618
  [data-roottale-cms] :where(.rt-cms-post-header .rt-cms-excerpt) {
@@ -630,24 +626,24 @@
630
626
  font-variant-numeric: tabular-nums;
631
627
  }
632
628
 
633
- /* 네이버 프리미엄콘텐츠·avcd 기준 문단 간 ≈24px. */
629
+ /* AVCD 읽기 기준: 본문 720px, 문단 간 24px. */
634
630
  [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] > * + *) {
635
- margin-block-start: 1.35em;
631
+ margin-block-start: 1.5rem;
636
632
  }
637
633
 
638
634
  /* 읽기 measure — rem 고정값. 72ch 는 각 블록의 font-size 기준으로 해석돼
639
635
  h2 같은 대활자 블록이 문단보다 넓어지는 문제가 있었다(ch 는 해당 요소의
640
636
  0 글자 폭 기준) — 컬럼 폭을 블록마다 다르게 만들지 않으려면 폰트 크기와
641
- 무관한 고정 단위가 필요. 어드민 에디터(.tiptap-content > *)와 1:1 파리티. */
637
+ 무관한 고정 단위가 필요. 테마의 --rt-cms-measure 재정의는 유지한다. */
642
638
  [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] > *) {
643
- max-inline-size: var(--rt-cms-measure, 42.5rem);
639
+ max-inline-size: var(--rt-cms-measure, 45rem);
644
640
  margin-inline: auto;
645
641
  }
646
642
 
647
643
  [data-roottale-cms] :where(.rt-archive-related) {
648
644
  display: grid;
649
645
  gap: var(--rt-spacing-4, 1rem);
650
- max-inline-size: var(--rt-cms-measure, 42.5rem);
646
+ max-inline-size: var(--rt-cms-measure, 45rem);
651
647
  margin-inline: auto;
652
648
  margin-block: var(--rt-spacing-6, 1.5rem) var(--rt-spacing-7, 2rem);
653
649
  padding: var(--rt-spacing-4, 1rem);
@@ -718,7 +714,7 @@
718
714
 
719
715
  /* W5-2 — 양식(필드 그룹) 스칼라 값 정보 패널 (연관 박스 아래). */
720
716
  [data-roottale-cms] :where(.rt-archive-facts) {
721
- max-inline-size: var(--rt-cms-measure, 42.5rem);
717
+ max-inline-size: var(--rt-cms-measure, 45rem);
722
718
  margin-inline: auto;
723
719
  margin-block: var(--rt-spacing-5, 1.25rem) var(--rt-spacing-7, 2rem);
724
720
  padding: var(--rt-spacing-4, 1rem);
@@ -759,267 +755,363 @@
759
755
  white-space: pre-line;
760
756
  }
761
757
 
762
- /* 주의 — 본문 최상위 블록의 margin 은 단축 속성 금지: inline 축을 0 으로 덮으면
763
- 컬럼 중앙 정렬(> * 의 margin-inline: auto)이 풀린다. margin-block 만 쓴다. */
764
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] p) {
765
- margin-block: 0;
766
- /* line-height 는 .rt-cms-body 의 1.8 을 그대로 상속 */
767
- text-wrap: pretty;
758
+ /* AVCD article 조판. li까지 reset을 복원하며 독립 본문에도 적용한다. */
759
+ :is([data-roottale-cms="body"], .rt-cms-body) {
760
+ min-width: 0;
761
+ max-width: var(--rt-cms-measure, 45rem);
762
+ margin-inline: auto;
763
+ font-family: var(--rt-font-body, "Pretendard Variable", Pretendard, system-ui, sans-serif);
764
+ color: var(--rt-color-foreground, #2b323c);
765
+ font-size: var(--rt-cms-body-size, 18px);
766
+ font-weight: 400;
767
+ line-height: 1.7;
768
+ letter-spacing: -0.03rem;
769
+ word-break: normal;
770
+ overflow-wrap: anywhere;
771
+ text-wrap: wrap;
768
772
  }
769
773
 
770
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] h2),
771
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] h3),
772
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] h4) {
773
- font-family: var(--rt-font-display, system-ui, sans-serif);
774
- color: var(--rt-color-foreground, #06162f);
775
- letter-spacing: 0;
776
- line-height: 1.4;
777
- text-wrap: balance;
778
- /* 목차 앵커 점프 시 sticky 헤더에 가리지 않게. */
779
- scroll-margin-block-start: var(--rt-cms-scroll-offset, 5rem);
774
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(:is(p, li, ul, ol)) {
775
+ line-height: inherit;
776
+ letter-spacing: inherit;
780
777
  }
781
778
 
782
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] h2) {
783
- margin-block: 2.8em 0.7em;
784
- font-size: var(--rt-font-size-3xl, 1.875rem);
785
- font-weight: var(--rt-font-weight-bold, 700);
779
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(p) {
780
+ margin-block: 0 24px;
786
781
  }
787
782
 
788
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] h3) {
789
- margin-block: 1.7em 0.5em;
790
- font-family: var(--rt-font-body, system-ui, sans-serif);
791
- font-size: 1.375rem;
792
- font-weight: var(--rt-font-weight-semibold, 600);
783
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(:is(h2, h3, h4)) {
784
+ padding: 0;
785
+ border: 0;
786
+ font-family: inherit;
787
+ color: var(--rt-color-primary, #082215);
788
+ letter-spacing: normal;
789
+ text-wrap: wrap;
790
+ word-break: normal;
791
+ overflow-wrap: anywhere;
792
+ scroll-margin-top: var(--rt-cms-scroll-offset, 5rem);
793
793
  }
794
794
 
795
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] h4) {
796
- margin-block: 1.4em 0.35em;
797
- font-family: var(--rt-font-body, system-ui, sans-serif);
798
- font-size: 1.1875rem;
799
- font-weight: var(--rt-font-weight-semibold, 600);
795
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(h2) {
796
+ margin-block: 110px 20px;
797
+ font-size: 32px;
798
+ --rt-cms-heading-size: 32px;
799
+ font-weight: 700;
800
+ line-height: 1.3;
800
801
  }
801
802
 
802
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] h2:first-child),
803
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] h3:first-child),
804
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] h4:first-child) {
805
- margin-block-start: 0;
803
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(h3) {
804
+ margin-block: 32px 12px;
805
+ font-size: 24px;
806
+ --rt-cms-heading-size: 24px;
807
+ font-weight: 600;
808
+ line-height: 1.4;
806
809
  }
807
810
 
808
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] h2 + p),
809
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] h3 + p),
810
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] h4 + p) {
811
- margin-block-start: 0;
811
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(h4) {
812
+ margin-block: 24px 8px;
813
+ font-size: 20px;
814
+ --rt-cms-heading-size: 20px;
815
+ font-weight: 600;
816
+ line-height: 1.4;
812
817
  }
813
818
 
814
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] ul),
815
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] ol) {
816
- padding-inline-start: 1.5em;
817
- margin-block: 0;
819
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(:is(strong, b)) {
820
+ font-weight: 700;
818
821
  }
819
822
 
820
- /* 고객 사이트의 CSS 리셋(Preflight 등)이 list-style 을 지워도 불릿/번호 유지. */
821
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] ul) {
822
- list-style: disc;
823
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(:is(em, i)) {
824
+ font-style: italic;
823
825
  }
824
826
 
825
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] ol) {
826
- list-style: decimal;
827
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(a) {
828
+ color: var(--rt-color-primary, #082215);
829
+ font-weight: inherit;
830
+ text-decoration: underline;
831
+ text-decoration-color: transparent;
832
+ text-decoration-thickness: 1px;
833
+ text-underline-offset: 3px;
834
+ transition: color 180ms ease, text-decoration-color 220ms ease;
827
835
  }
828
836
 
829
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] ul ul) {
830
- list-style: circle;
837
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(a:hover, a:active, a:focus-visible) {
838
+ text-decoration-color: currentColor;
831
839
  }
832
840
 
833
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] ul ul ul) {
834
- list-style: square;
841
+ @media (prefers-reduced-motion: reduce) {
842
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(a) { transition: none; }
835
843
  }
836
844
 
837
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] li) {
838
- text-wrap: pretty;
845
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(a:focus-visible) {
846
+ outline: 2px solid var(--rt-color-primary, #082215);
847
+ outline-offset: 3px;
839
848
  }
840
849
 
841
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] li + li) {
842
- margin-block-start: 0.4em;
850
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(:is(ul, ol)) {
851
+ margin-block: 0 24px;
852
+ padding-inline-start: 24px;
853
+ list-style-position: outside;
843
854
  }
844
855
 
845
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] li > p) {
846
- margin: 0;
856
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(ul) {
857
+ list-style-type: disc;
847
858
  }
848
859
 
849
- /* avcd 식 액센트 마커. */
850
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] ul li)::marker {
851
- color: color-mix(in srgb, var(--rt-color-primary, #06162f) 72%, transparent);
860
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(ol) {
861
+ list-style-type: decimal;
852
862
  }
853
863
 
854
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] ol li)::marker {
855
- color: color-mix(in srgb, var(--rt-color-primary, #06162f) 85%, transparent);
856
- font-weight: 600;
857
- font-variant-numeric: tabular-nums;
864
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(ul ul) {
865
+ list-style-type: circle;
858
866
  }
859
867
 
860
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] blockquote) {
861
- border: 1px solid color-mix(in srgb, var(--rt-color-border, #dceef3) 88%, transparent);
862
- border-radius: min(var(--rt-radius-md, 0.5rem), 0.625rem);
863
- background: color-mix(in srgb, var(--rt-color-muted, #f7f8f7) 32%, transparent);
864
- padding: 1.125rem 1.25rem;
865
- /* 본문 최상위 블록 — margin 단축 금지(중앙 정렬 유지), margin-block 만. */
866
- margin-block: 1.6em;
867
- color: color-mix(in srgb, var(--rt-color-foreground, #06162f) 82%, transparent);
868
- /* font-style: italic 제거 — 한글 가짜 기울임 방지. */
868
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(ul ul ul) {
869
+ list-style-type: square;
869
870
  }
870
871
 
871
- /* 카드 내부 리듬 — 본문 owl(> * + *)은 최상위 전용이라 인용구 안 문단 간격은
872
- 여기서 별도 부여. */
873
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] blockquote > * + *) {
874
- margin-block-start: 0.75em;
872
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(li) {
873
+ display: list-item;
874
+ list-style: inherit;
875
+ margin: 0 0 20px;
876
+ padding: 0;
875
877
  }
876
878
 
877
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] a) {
878
- color: var(--rt-color-primary, #06162f);
879
- text-decoration: underline;
880
- text-decoration-thickness: 1px;
881
- text-decoration-color: color-mix(in srgb, var(--rt-color-primary, #06162f) 42%, transparent);
882
- text-underline-offset: 0.18em;
883
- transition: text-decoration-color 140ms ease;
879
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(li + li) {
880
+ margin-top: 0;
884
881
  }
885
882
 
886
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] a:hover),
887
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] a:focus-visible) {
888
- text-decoration-color: var(--rt-color-primary, #06162f);
883
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(li > :is(ul, ol)) {
884
+ margin-block: 20px 0;
889
885
  }
890
886
 
891
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] mark) {
892
- border-radius: var(--rt-radius-sm, 0.25rem);
893
- padding-inline: 0.1em;
894
- background: var(--rt-color-highlight, #fef3c7);
895
- color: inherit;
896
- box-decoration-break: clone;
897
- -webkit-box-decoration-break: clone;
887
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(li > p) {
888
+ margin-block: 0;
898
889
  }
899
890
 
900
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] u) {
901
- text-underline-offset: 0.16em;
902
- text-decoration-thickness: 0.08em;
891
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(ul > li::marker) {
892
+ color: var(--rt-color-primary, #082215);
893
+ font-size: 0.85em;
903
894
  }
904
895
 
905
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] s) {
906
- text-decoration-thickness: 0.08em;
896
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(ol > li::marker) {
897
+ color: var(--rt-color-primary, #082215);
898
+ font-weight: 700;
907
899
  }
908
900
 
909
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] code) {
910
- border-radius: var(--rt-radius-sm, 0.25rem);
911
- background: var(--rt-color-muted, #f7f8f7);
912
- padding-inline: 0.25em;
913
- font-family: var(--rt-font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace);
914
- font-size: 0.9em;
901
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(blockquote) {
902
+ margin-block: 32px;
903
+ padding: 24px;
904
+ border: 0.5px solid rgb(154 164 177 / 50%);
905
+ border-radius: 8px;
906
+ background: transparent;
907
+ color: var(--rt-color-foreground, #2b323c);
908
+ font-size: inherit;
909
+ font-weight: 400;
910
+ line-height: inherit;
911
+ font-style: normal;
915
912
  }
916
913
 
917
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] pre) {
918
- overflow-x: auto;
919
- border-radius: var(--rt-radius-md, 0.5rem);
920
- background: var(--rt-color-muted, #f7f8f7);
921
- padding: var(--rt-spacing-3, 0.75rem);
922
- font-family: var(--rt-font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace);
923
- font-size: 0.9em;
924
- /* 코드는 어절 조판 대상 아님 — 가로 스크롤로 원문 유지. */
925
- word-break: normal;
926
- overflow-wrap: normal;
914
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(blockquote p) {
915
+ margin-bottom: 0;
927
916
  }
928
917
 
929
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] pre code) {
918
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(blockquote p + p) {
919
+ margin-top: 24px;
920
+ }
921
+
922
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(hr) {
923
+ margin-block: 40px;
924
+ border: 0;
925
+ border-top: 1px solid #e5e9ee;
926
+ }
927
+
928
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(:is(img, video, iframe)) {
930
929
  display: block;
931
- padding: 0;
932
- background: transparent;
930
+ max-width: 100%;
931
+ height: auto;
932
+ border: 0;
933
+ border-radius: 8px;
934
+ margin: 32px auto;
933
935
  }
934
936
 
935
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] img) {
936
- display: block; /* 인라인 하단 갭 제거 */
937
- max-inline-size: 100%;
938
- block-size: auto;
939
- border-radius: var(--rt-radius-md, 0.5rem);
940
- margin-block: 2em;
937
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(:is(img, video, iframe)) {
938
+ width: 100%;
939
+ }
940
+
941
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(iframe) {
942
+ aspect-ratio: 16 / 9;
941
943
  }
942
944
 
943
- /* figure — 최상위 블록. margin 은 figure 가 소유(margin-block 만, 중앙 정렬 유지). */
944
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] figure) {
945
- margin-block: 2em;
945
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(figure) {
946
+ max-width: 100%;
947
+ margin: 32px auto;
946
948
  }
947
949
 
948
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] figure img) {
950
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(figure :is(img, video, iframe)) {
949
951
  margin-block: 0;
950
952
  }
951
953
 
952
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] figcaption) {
953
- margin-block-start: 0.625rem;
954
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(figcaption) {
955
+ margin-block: 8px 0;
956
+ color: #9aa4b1;
957
+ font-size: 15px;
958
+ font-style: italic;
959
+ line-height: 1.7;
954
960
  text-align: center;
955
- color: color-mix(in srgb, var(--rt-color-foreground, #06162f) 52%, transparent);
956
- font-size: 0.875rem;
957
- line-height: 1.55;
958
- /* italic 쓰지 말 것 — 한글 가짜 기울임 금지. */
959
961
  }
960
962
 
961
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] hr) {
963
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(pre) {
964
+ max-width: 100%;
965
+ overflow-x: auto;
966
+ margin-block: 24px;
967
+ padding: 16px 20px;
962
968
  border: 0;
963
- border-block-start: 1px solid color-mix(in srgb, var(--rt-color-border, #dceef3) 90%, transparent);
964
- margin-block: 2.5rem;
969
+ border-radius: 8px;
970
+ background: #f0f2f5;
971
+ color: var(--rt-color-foreground, #2b323c);
972
+ white-space: pre;
973
+ word-break: normal;
974
+ overflow-wrap: normal;
965
975
  }
966
976
 
967
- /* 본문 텍스트 선택 색 — 프라이머리 색으로 브랜드 일관성. */
968
- [data-roottale-cms] :where(.rt-cms-article) ::selection {
969
- background: color-mix(in srgb, var(--rt-color-primary, #06162f) 14%, transparent);
977
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(code) {
978
+ font-family: Consolas, Monaco, monospace;
970
979
  }
971
980
 
972
- /* 표(table) — 좁은 화면에서 가로 스크롤(wrap), 셀 경계선·머리행 강조.
973
- 에디터(ProseMirror)는 맨 table — 발행 .rt-table 과 같은 룰을 element 로도
974
- 적용(에디터-뷰어 단일 소스). 발행 HTML 의 table 은 .rt-table 이면서 table 이므로
975
- 중복 적용돼도 동일 값이라 무해함. */
976
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] .rt-table-wrap) {
977
- overflow-x: auto;
981
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(:not(pre) > code) {
982
+ padding: 2px 6px;
983
+ border-radius: 4px;
984
+ background: #f0f2f5;
985
+ color: var(--rt-color-foreground, #2b323c);
986
+ font-size: 0.875em;
978
987
  }
979
988
 
980
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] .rt-table),
981
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] table) {
982
- inline-size: 100%;
989
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(pre code) {
990
+ display: block;
991
+ padding: 0;
992
+ border: 0;
993
+ background: transparent;
994
+ color: inherit;
995
+ font-size: 16px;
996
+ line-height: 1.7;
997
+ }
998
+
999
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(table) {
1000
+ display: table;
1001
+ width: 100%;
1002
+ max-width: 100%;
1003
+ margin-block: 24px;
1004
+ border: 1px solid #d6dbe2;
1005
+ border-radius: 8px;
983
1006
  border-collapse: separate;
984
1007
  border-spacing: 0;
985
- border: 1px solid var(--rt-color-border, #dceef3);
986
- border-radius: min(var(--rt-radius-md, 0.5rem), 0.625rem);
987
1008
  overflow: hidden;
988
- font-size: 0.9375em;
1009
+ font-size: 17px;
1010
+ line-height: 1.7;
989
1011
  }
990
1012
 
991
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] .rt-table th),
992
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] .rt-table td),
993
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] table th),
994
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] table td) {
1013
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(:is(th, td)) {
1014
+ min-width: 0;
1015
+ padding: 20px 14px;
995
1016
  border: 0;
996
- border-block-end: 1px solid color-mix(in srgb, var(--rt-color-border, #dceef3) 80%, transparent);
997
- border-inline-end: 1px solid color-mix(in srgb, var(--rt-color-border, #dceef3) 55%, transparent);
998
- padding: 0.625rem 0.875rem;
999
- text-align: start;
1017
+ border-right: 1px solid #d6dbe2;
1018
+ border-bottom: 1px solid #d6dbe2;
1019
+ color: var(--rt-color-foreground, #2b323c);
1020
+ text-align: left;
1000
1021
  vertical-align: top;
1022
+ word-break: break-all;
1001
1023
  }
1002
1024
 
1003
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] .rt-table th:last-child),
1004
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] .rt-table td:last-child),
1005
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] table th:last-child),
1006
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] table td:last-child) {
1007
- border-inline-end: 0;
1025
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(:is(th, td):last-child) {
1026
+ border-right: 0;
1008
1027
  }
1009
1028
 
1010
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] .rt-table tr:last-child > th),
1011
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] .rt-table tr:last-child > td),
1012
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] table tr:last-child > th),
1013
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] table tr:last-child > td) {
1014
- border-block-end: 0;
1029
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(tr:last-child > :is(th, td)) {
1030
+ border-bottom: 0;
1015
1031
  }
1016
1032
 
1017
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] .rt-table th),
1018
- [data-roottale-cms] :where(.rt-cms-article [data-roottale-cms="body"] table th) {
1019
- background: color-mix(in srgb, var(--rt-color-muted, #f7f8f7) 72%, white);
1020
- font-weight: 600;
1033
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(th) {
1034
+ background: #e5e9ee;
1035
+ font-weight: 700;
1036
+ }
1037
+
1038
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(td) {
1039
+ background: #fff;
1040
+ font-weight: 500;
1041
+ }
1042
+
1043
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(td:first-child) {
1044
+ background: #e5e9ee;
1045
+ font-weight: 700;
1046
+ }
1047
+
1048
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(:is(th, td) p) {
1049
+ margin-bottom: 0;
1050
+ }
1051
+
1052
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(u) {
1053
+ text-underline-offset: 3px;
1054
+ }
1055
+
1056
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(s) {
1057
+ text-decoration: line-through;
1058
+ }
1059
+
1060
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(mark) {
1061
+ background: #fef3c7;
1062
+ color: inherit;
1063
+ }
1064
+
1065
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(> :first-child) {
1066
+ margin-top: 0;
1067
+ }
1068
+
1069
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(> :last-child) {
1070
+ margin-bottom: 0;
1021
1071
  }
1022
1072
 
1073
+ @media (max-width: 767px) {
1074
+ [data-roottale-cms] :where(.rt-cms-post-header .rt-cms-title) {
1075
+ font-size: 28px;
1076
+ font-weight: var(--rt-font-weight-semibold, 600);
1077
+ line-height: 1.3;
1078
+ letter-spacing: -0.03em;
1079
+ }
1080
+ [data-roottale-cms] :where(.rt-cms-post-header .rt-cms-excerpt) {
1081
+ font-size: var(--rt-cms-body-size, 17px);
1082
+ }
1083
+ :is([data-roottale-cms="body"], .rt-cms-body) {
1084
+ font-size: var(--rt-cms-body-size, 17px);
1085
+ }
1086
+ /* 저장된 고정 크기·행간도 모바일에서는 본문과 소제목의 읽기 크기를 따른다. */
1087
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(:is(p, li, div, span, strong, b, em, i)[style*="font-size"]) {
1088
+ font-size: inherit !important;
1089
+ }
1090
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(:is(p, li, div, span, strong, b, em, i)[style*="line-height"]) {
1091
+ line-height: inherit !important;
1092
+ }
1093
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(h2) {
1094
+ font-size: 22px;
1095
+ --rt-cms-heading-size: 22px;
1096
+ margin-bottom: 16px;
1097
+ }
1098
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(h3) {
1099
+ font-size: 20px;
1100
+ --rt-cms-heading-size: 20px;
1101
+ }
1102
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(h4) {
1103
+ font-size: 18px;
1104
+ --rt-cms-heading-size: 18px;
1105
+ }
1106
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(table) {
1107
+ font-size: 15px;
1108
+ }
1109
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(:is(th, td)) {
1110
+ padding: 16px 14px;
1111
+ }
1112
+ }
1113
+
1114
+ :is([data-roottale-cms="body"], .rt-cms-body) :where(.rt-table-wrap) { max-width: 100%; overflow-x: auto; }
1023
1115
  /* 공식 출처 — 일반 목록과 구분되는 근거 묶음. */
1024
1116
  [data-roottale-cms] :where(.rt-cms-references) {
1025
1117
  padding: var(--rt-spacing-5, 1.25rem);
@@ -1039,7 +1131,7 @@
1039
1131
 
1040
1132
  /* 공통 블록 이전을 마치지 않은 사이트의 글 하단 CTA. */
1041
1133
  [data-roottale-cms] :where(.rt-cms-post-cta) {
1042
- max-inline-size: var(--rt-cms-measure, 42.5rem);
1134
+ max-inline-size: var(--rt-cms-measure, 45rem);
1043
1135
  margin-inline: auto;
1044
1136
  margin-block-start: var(--rt-spacing-6, 1.5rem);
1045
1137
  padding: var(--rt-spacing-5, 1.25rem);
@@ -1082,7 +1174,7 @@
1082
1174
  /* 공통 블록(post_footer) — 본문 바로 아래, 본문과 같은 폭. 모양은 어드민 표시 형태
1083
1175
  (data-pattern-layout / data-pattern-link-style / --rt-pattern-bg / --rt-pattern-btn-n)를 따른다. */
1084
1176
  [data-roottale-cms] :where(.rt-cms-post-pattern) {
1085
- max-inline-size: var(--rt-cms-measure, 42.5rem);
1177
+ max-inline-size: var(--rt-cms-measure, 45rem);
1086
1178
  margin-inline: auto;
1087
1179
  margin-block-start: var(--rt-spacing-6, 1.5rem);
1088
1180
  }
@@ -1199,7 +1291,7 @@
1199
1291
 
1200
1292
  /* 관련 글 (rt-cms-related) — 글 하단 같은 카테고리 최근 글. */
1201
1293
  [data-roottale-cms] :where(.rt-cms-related) {
1202
- max-inline-size: var(--rt-cms-measure, 42.5rem);
1294
+ max-inline-size: var(--rt-cms-measure, 45rem);
1203
1295
  margin-inline: auto;
1204
1296
  margin-block: var(--rt-spacing-8, 2.5rem) var(--rt-spacing-6, 1.5rem);
1205
1297
  }
@@ -1250,7 +1342,7 @@
1250
1342
  [data-roottale-cms] :where(.rt-cms-toc) {
1251
1343
  position: relative;
1252
1344
  /* 본문 measure 와 동일 폭으로 정렬(본문 위 인라인 배치). */
1253
- max-inline-size: var(--rt-cms-measure, 42.5rem);
1345
+ max-inline-size: var(--rt-cms-measure, 45rem);
1254
1346
  margin-inline: auto;
1255
1347
  background: color-mix(in srgb, var(--rt-color-muted, #f7f8f7) 34%, white);
1256
1348
  border: 1px solid color-mix(in srgb, var(--rt-color-border, #dceef3) 86%, transparent);
@@ -1400,7 +1492,7 @@
1400
1492
  display: flex;
1401
1493
  align-items: center;
1402
1494
  gap: var(--rt-spacing-4, 1rem);
1403
- max-inline-size: var(--rt-cms-measure, 42.5rem);
1495
+ max-inline-size: var(--rt-cms-measure, 45rem);
1404
1496
  margin-inline: auto;
1405
1497
  margin-block-start: var(--rt-spacing-8, 3rem);
1406
1498
  border: 1px solid color-mix(in srgb, var(--rt-color-border, #dceef3) 82%, transparent);
@@ -1483,23 +1575,27 @@
1483
1575
  margin-inline: max(
1484
1576
  0rem,
1485
1577
  calc(
1486
- (100cqi - var(--rt-cms-measure, 42.5rem) - 15rem - var(--rt-spacing-6, 1.5rem)) / 2
1578
+ (100cqi - var(--rt-cms-measure, 45rem) - 15rem - var(--rt-spacing-6, 1.5rem)) / 2
1487
1579
  )
1488
1580
  )
1489
1581
  auto;
1490
1582
  }
1491
1583
  }
1492
1584
 
1493
- @media (max-width: 640px) {
1494
- [data-roottale-cms] :where(.rt-cms-title) {
1495
- font-size: var(--rt-font-size-2xl, 1.5rem);
1585
+ @media (max-width: 767px) {
1586
+ [data-roottale-cms] :where(.rt-cms-toc) {
1587
+ padding: 9px 16px;
1496
1588
  }
1589
+ [data-roottale-cms] :where(.rt-cms-toc-summary) {
1590
+ box-sizing: border-box;
1591
+ min-block-size: 32px;
1592
+ line-height: 20px;
1593
+ }
1594
+ }
1497
1595
 
1498
- /* .rt-cms-post-header .rt-cms-title 는 clamp() 가 이미 좁은 화면 크기를
1499
- 처리하므로 별도 오버라이드 불필요(제거됨). */
1500
-
1501
- [data-roottale-cms] :where(.rt-cms-toc) {
1502
- padding: 1.125rem;
1596
+ @media (max-width: 640px) {
1597
+ [data-roottale-cms] :where(.rt-cms-title:not(.rt-cms-post-header .rt-cms-title)) {
1598
+ font-size: var(--rt-font-size-2xl, 1.5rem);
1503
1599
  }
1504
1600
 
1505
1601
  [data-roottale-cms] :where(.rt-cms-toc-item a) {
@@ -1510,12 +1606,6 @@
1510
1606
  align-items: flex-start;
1511
1607
  }
1512
1608
 
1513
- /* 모바일 본문 — 데스크톱보다 살짝 낮춘 스케일(1.0625 = 17px 기준). */
1514
- [data-roottale-cms] :where(.rt-cms-body),
1515
- [data-roottale-cms] :where([data-roottale-cms="body"]) {
1516
- font-size: var(--rt-cms-body-size, calc(var(--rt-font-size-base, 1rem) * 1.0625));
1517
- }
1518
-
1519
1609
  /* 브레드크럼 — 좁은 화면은 말줄임 대신 자연 줄바꿈 허용(가로 스크롤 방지). */
1520
1610
  [data-roottale-cms] :where(.rt-cms-breadcrumb li[aria-current="page"]) {
1521
1611
  overflow: visible;
@@ -1689,3 +1779,61 @@
1689
1779
  outline: 2px solid var(--rt-color-primary, #06162f);
1690
1780
  outline-offset: 2px;
1691
1781
  }
1782
+
1783
+ /* 본문 이미지 확대. 포털은 콘텐츠 CSS·overflow 경계 밖에 놓인다. */
1784
+ [data-rt-image-zoom] { cursor: zoom-in; }
1785
+ [data-rt-image-zoom]:focus-visible { outline: 2px solid #3161b1; outline-offset: 4px; }
1786
+
1787
+ dialog.rt-cms-image-dialog {
1788
+ box-sizing: border-box;
1789
+ position: fixed;
1790
+ inset: 0;
1791
+ width: 100vw;
1792
+ max-width: none;
1793
+ height: 100dvh;
1794
+ max-height: none;
1795
+ margin: 0;
1796
+ padding: 20px;
1797
+ border: 0;
1798
+ color: #fff;
1799
+ background: transparent;
1800
+ overflow: hidden;
1801
+ }
1802
+
1803
+ .rt-cms-image-dialog[open] { display: flex; flex-direction: column; gap: 16px; animation: rt-image-reveal 180ms ease-out; }
1804
+ .rt-cms-image-dialog::backdrop { background: rgb(10 15 22 / 92%); }
1805
+ .rt-cms-image-dialog__toolbar { display: flex; justify-content: flex-end; gap: 12px; flex: 0 0 auto; }
1806
+ .rt-cms-image-dialog__toolbar button {
1807
+ display: inline-flex;
1808
+ align-items: center;
1809
+ gap: 12px;
1810
+ min-height: 44px;
1811
+ padding: 8px 16px;
1812
+ border: 1px solid rgb(255 255 255 / 35%);
1813
+ border-radius: 6px;
1814
+ color: #fff;
1815
+ background: rgb(255 255 255 / 8%);
1816
+ font: 500 14px/1.5 "Pretendard Variable", sans-serif;
1817
+ cursor: pointer;
1818
+ transition: background-color 180ms ease;
1819
+ }
1820
+ .rt-cms-image-dialog__toolbar button:hover { background: rgb(255 255 255 / 20%); }
1821
+ .rt-cms-image-dialog__toolbar button:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
1822
+ .rt-cms-image-dialog__toolbar span { font-size: 24px; line-height: 1; }
1823
+ .rt-cms-image-dialog__viewport { flex: 1 1 0; min-height: 0; overflow: auto; overscroll-behavior: contain; text-align: center; }
1824
+ .rt-cms-image-dialog__viewport img {
1825
+ display: block;
1826
+ width: auto;
1827
+ height: auto;
1828
+ max-width: 100%;
1829
+ max-height: 100%;
1830
+ margin: auto;
1831
+ object-fit: contain;
1832
+ }
1833
+ .rt-cms-image-dialog__viewport[data-enlarged='true'] img { max-width: none; max-height: none; }
1834
+ @keyframes rt-image-reveal { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
1835
+ @media (max-width: 600px) { dialog.rt-cms-image-dialog { padding: 12px; gap: 12px; } }
1836
+ @media (prefers-reduced-motion: reduce) {
1837
+ .rt-cms-image-dialog[open] { animation: none; }
1838
+ .rt-cms-image-dialog__toolbar button { transition: none; }
1839
+ }