-
{d.sectionTitle}
-
-
+
+
+
-
-
-
-
-
- {d.cta.headingPlain} {d.cta.headingEm}
-
-
- {d.cta.body}
-
-
- {d.cta.button}
-
-
-
-
+
+ }
+ />
+
);
}
diff --git a/app/icon.png b/app/icon.png
new file mode 100644
index 0000000..ac6036d
Binary files /dev/null and b/app/icon.png differ
diff --git a/app/redesign-overrides.css b/app/redesign-overrides.css
new file mode 100644
index 0000000..5d4cf82
--- /dev/null
+++ b/app/redesign-overrides.css
@@ -0,0 +1,508 @@
+/*
+ * Next.js-specific adjustments on top of the generated app/redesign.css.
+ * Keep prototype styles in redesign.css (regenerate it with
+ * scripts/scope-prototype-css.py) and put anything hand-written here.
+ */
+
+/* globals.css gives legacy headings Lora; the redesign uses one family. */
+.rd h1,
+.rd h2,
+.rd h3,
+.rd h4 {
+ font-family: var(--font);
+}
+.rd ul,
+.rd ol {
+ margin: 0;
+}
+.rd .sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border: 0;
+}
+.rd button {
+ font-family: inherit;
+}
+
+/* ---------- Header ---------- */
+.rd-hdr {
+ z-index: 100;
+ -webkit-backdrop-filter: blur(12px);
+}
+.rd-hdr .nav {
+ gap: 16px;
+}
+.rd-hdr .right {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+.rd-hdr .lang {
+ position: relative;
+}
+.rd-hdr .lang > button {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ font: inherit;
+ font-weight: 600;
+ font-size: 0.92rem;
+ color: var(--ink);
+ background: transparent;
+ border: 1px solid var(--line);
+ border-radius: 999px;
+ padding: 8px 14px;
+ cursor: pointer;
+}
+.rd-hdr .lang > button:hover {
+ background: var(--tint);
+}
+.rd-hdr .lang ul {
+ position: absolute;
+ right: 0;
+ top: calc(100% + 8px);
+ min-width: 190px;
+ list-style: none;
+ padding: 8px;
+ background: #fff;
+ border: 1px solid var(--line);
+ border-radius: 16px;
+ box-shadow: 0 20px 40px -20px rgba(42, 15, 49, 0.3);
+ z-index: 5;
+}
+[dir="rtl"] .rd-hdr .lang ul {
+ right: auto;
+ left: 0;
+}
+.rd-hdr .lang li button {
+ display: block;
+ width: 100%;
+ text-align: start;
+ font: inherit;
+ font-size: 0.95rem;
+ color: var(--ink);
+ background: none;
+ border: 0;
+ border-radius: 10px;
+ padding: 9px 12px;
+ cursor: pointer;
+}
+.rd-hdr .lang li button:hover,
+.rd-hdr .lang li button[aria-selected="true"] {
+ background: var(--tint);
+ color: var(--purple);
+}
+.rd-hdr .lang li button[aria-selected="true"] {
+ font-weight: 700;
+}
+/* The language picker takes room, so collapse to the burger a bit earlier. */
+@media (max-width: 1080px) {
+ .rd-hdr .links {
+ display: none;
+ }
+ .rd-hdr .burger {
+ display: block;
+ }
+ .rd-hdr.open .links {
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ gap: 2px;
+ position: absolute;
+ top: 76px;
+ left: 0;
+ right: 0;
+ background: #fff;
+ padding: 14px 20px 24px;
+ border-bottom: 1px solid var(--line);
+ max-height: calc(100dvh - 76px);
+ overflow: auto;
+ }
+ .rd-hdr.open .drop {
+ display: flex;
+ position: static;
+ border: 0;
+ box-shadow: none;
+ padding: 0 0 6px 14px;
+ min-width: 0;
+ }
+ .rd-hdr .links .btn {
+ margin: 10px 0 0;
+ }
+}
+
+/* ---------- Home ---------- */
+.rd .hero-photo img {
+ height: auto;
+}
+.rd .strip h2 {
+ font-size: 1rem;
+ font-weight: 700;
+ letter-spacing: 0;
+}
+.rd .sources {
+ list-style: none;
+ padding: 0;
+}
+.rd .pir-tags {
+ list-style: none;
+ padding: 0;
+}
+.rd .pir-tags li {
+ background: var(--tint);
+ border-radius: 999px;
+ padding: 6px 12px;
+ font-weight: 700;
+ font-size: 0.92rem;
+ line-height: 1.3;
+}
+.rd .pv .h2 {
+ margin-top: 14px;
+}
+.rd .pv .lede {
+ margin-top: 16px;
+}
+.rd .pv .btn {
+ margin-top: 26px;
+}
+.rd .pv-photo img {
+ width: auto;
+ height: auto;
+}
+.rd .aisteps {
+ list-style: none;
+ padding: 0;
+}
+.rd .ai-tips .ctas {
+ margin-top: 28px;
+}
+.rd .checks svg {
+ width: 22px;
+ height: 22px;
+}
+.rd .pcard {
+ display: block;
+ text-align: start;
+}
+.rd .pcard-line {
+ border: 1px solid var(--line);
+ transition:
+ border-color 0.2s,
+ box-shadow 0.2s;
+}
+.rd .pcard-line:hover {
+ border-color: var(--purple);
+ box-shadow: 0 24px 48px -28px rgba(94, 26, 107, 0.45);
+}
+.rd .story-body .btn {
+ margin-top: 6px;
+}
+.rd .rotator span {
+ transition:
+ opacity 0.35s,
+ transform 0.35s;
+}
+
+/* ---------- Right-to-left locales ---------- */
+[dir="rtl"] .rd .campus-go svg,
+[dir="rtl"] .rd .arrow-flip {
+ transform: scaleX(-1);
+}
+[dir="rtl"] .rd .campus:hover .campus-go svg {
+ transform: scaleX(-1) translateX(4px);
+}
+[dir="rtl"] .rd .soc-go {
+ right: auto;
+ left: 20px;
+}
+
+/* ---------- Shared ---------- */
+.rd .inline-link {
+ color: var(--purple);
+ font-weight: 700;
+}
+.rd .inline-link:hover {
+ text-decoration: underline;
+}
+
+/* ---------- About ---------- */
+.rd .a-hero p {
+ margin-left: auto;
+ margin-right: auto;
+}
+.rd .fv-section {
+ padding-top: 88px;
+}
+.rd .pull {
+ margin-inline: 0;
+}
+.rd figure.quote-band {
+ margin: 0;
+}
+.rd .quote-band blockquote {
+ margin: 0;
+}
+
+/* ---------- Team ---------- */
+/* The campus filter toggles are buttons with aria-pressed, not tabs. */
+.rd .tabs button[aria-pressed="true"] {
+ background: var(--purple);
+ color: #fff;
+}
+.rd .avatar-img {
+ width: 96px;
+ height: 96px;
+}
+.rd .vbox {
+ margin: auto;
+}
+.rd .team-cta section {
+ padding-top: 0;
+}
+
+/* ---------- Projects ---------- */
+.rd .chips-sm {
+ list-style: none;
+ padding: 0;
+}
+.rd .chips-sm li {
+ background: var(--tint);
+ color: var(--ink);
+ border-radius: 999px;
+ padding: 4px 12px;
+ font-size: 0.9rem;
+ font-weight: 600;
+}
+.rd .pir-tags li.bad {
+ background: #fbe1df;
+ color: #7a1a14;
+}
+.rd .pir-tags li.loc {
+ background: var(--purple);
+ color: #fff;
+}
+.rd .pir-note {
+ text-align: start;
+}
+.rd .pir-photo img {
+ width: auto;
+ height: auto;
+}
+.rd .pir h4:focus,
+.rd .pir-verdict:focus {
+ outline: none;
+}
+/* Clear both the site header and the sticky track nav when jumping here. */
+.rd #pir {
+ scroll-margin-top: 170px;
+}
+.rd .track-nav .wrap {
+ position: relative;
+}
+
+/* ---------- Inspection ---------- */
+/* Clip the zoomed engine to its own box so, on mobile, the card can sit
+ below it without the zoomed image spilling over the page. */
+.rd .insp-view {
+ position: absolute;
+ inset: 0;
+ overflow: hidden;
+ border-radius: inherit;
+}
+.rd .insp-zoom img {
+ height: 100%;
+}
+@media (max-width: 900px) {
+ .rd .insp-frame {
+ background: none;
+ box-shadow: none;
+ }
+ .rd .insp-frame::before {
+ display: none;
+ }
+ .rd .insp-view {
+ position: relative;
+ inset: auto;
+ aspect-ratio: 3/2;
+ border-radius: 18px;
+ background: #e9e9ee;
+ box-shadow: 0 30px 60px -30px rgba(42, 15, 49, 0.45);
+ }
+ .rd .insp-zoom,
+ .rd .insp-hots {
+ height: auto;
+ padding-bottom: 0;
+ bottom: 0;
+ }
+}
+.rd .notlist b {
+ display: block;
+}
+.rd .where-rec {
+ border: 2px solid var(--purple);
+}
+.rd .where-rec .tag {
+ margin-bottom: 12px;
+}
+.rd .dealers-title {
+ font-size: 1.5rem;
+}
+.rd .dealers-body {
+ margin-top: 10px;
+}
+.rd .acc-outro {
+ margin-top: 12px;
+}
+.rd .quote-pad section {
+ padding-top: 88px;
+}
+.rd .mt18 {
+ margin-top: 18px;
+}
+.rd .h3-sm {
+ font-size: 1.25rem;
+}
+
+/* ---------- Fraud ---------- */
+.rd .fs-cell b,
+.rd .fs-pay s {
+ font-family: var(--font-caveat), "Caveat", "Segoe Print", cursive;
+}
+.rd .nw h3,
+.rd .nw-dek {
+ font-family: var(--font-bitter), "Bitter", Georgia, serif;
+}
+.rd .flip {
+ display: block;
+ width: 100%;
+ text-align: start;
+}
+.rd .bro .h2,
+.rd .bro .lede {
+ margin-top: 14px;
+}
+.rd .fs .ctas,
+.rd .fs .say {
+ margin-top: 20px;
+}
+.rd .fs .ai-src {
+ text-align: start;
+}
+.rd .apr-bar-key .k2.red {
+ background: var(--red);
+}
+@media (max-width: 760px) {
+ /* Put the contract card above the scene so the day badge can't cover it. */
+ .rd .yoyo-stage {
+ display: flex;
+ flex-direction: column;
+ }
+ .rd .yy-contract {
+ order: -1;
+ }
+ .rd .yy-day {
+ top: 0;
+ bottom: auto;
+ font-size: 0.8rem;
+ padding: 4px 12px;
+ white-space: nowrap;
+ }
+}
+@media (max-width: 560px) {
+ /* The hidden-term strip wraps to two lines here; give it room. */
+ .rd .fs-paper-wrap {
+ padding-bottom: 96px;
+ }
+ .rd .fs-hidden {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 2px;
+ transform: translateY(-96px);
+ }
+ .rd .fs-hidden.out {
+ transform: none;
+ }
+}
+
+/* ---------- Documents ---------- */
+.rd .guide-explorer {
+ grid-template-columns: 0.8fr 1.2fr;
+}
+@media (max-width: 960px) {
+ .rd .guide-explorer {
+ grid-template-columns: 1fr;
+ }
+}
+.rd .guide-explorer .acc {
+ margin-top: 0;
+}
+.rd .guide-explorer summary .tag {
+ margin-inline-end: 10px;
+}
+
+/* ---------- Get Involved ---------- */
+.rd .apply-wrap {
+ max-width: 900px;
+}
+.rd ul.roles {
+ list-style: none;
+ padding: 0;
+}
+.rd .roles li {
+ background: var(--bg);
+ border-radius: 18px;
+ padding: 22px;
+}
+.rd .roles li b {
+ display: block;
+ font-size: 1.1rem;
+ margin-bottom: 4px;
+}
+.rd .form-note:empty,
+.rd .form-ok:empty {
+ display: none;
+}
+.rd .form-note {
+ color: var(--red);
+}
+/* Long option text shouldn't stretch the grid past the viewport. */
+.rd form.apply > * {
+ min-width: 0;
+}
+.rd .fld input,
+.rd .fld select,
+.rd .fld textarea {
+ width: 100%;
+ min-width: 0;
+}
+.rd .radios input {
+ width: auto;
+}
+
+/* ---------- Dealer Map ---------- */
+.rd .nw-img img {
+ display: block;
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+.rd .news-note {
+ margin-top: 22px;
+}
+.rd .vd-launch:focus-visible {
+ outline: 3px solid var(--purple);
+ outline-offset: 4px;
+}
+[dir="rtl"] .rd-hdr .drop {
+ left: auto;
+ right: 0;
+}
+.rd .law-notice {
+ margin: 0 0 20px;
+}
diff --git a/app/redesign.css b/app/redesign.css
new file mode 100644
index 0000000..7724ad7
--- /dev/null
+++ b/app/redesign.css
@@ -0,0 +1,1328 @@
+/*
+ * GENERATED by scripts/scope-prototype-css.py from the redesign prototype.
+ * Do not edit by hand: put adjustments in app/redesign-overrides.css.
+ */
+
+/* Pages that use the redesign get a white canvas and no grain overlay. */
+body:has(.rd-page){background:#fff;color:#2a0f31}
+body:has(.rd-page)::after{display:none}
+html:has(.rd-page){scroll-behavior:smooth;scroll-padding-top:calc(env(safe-area-inset-top,0px) + 90px)}
+@media (prefers-reduced-motion:reduce){html:has(.rd-page){scroll-behavior:auto}}
+
+.rd{box-sizing:border-box;
+ color-scheme:light;
+ --purple:#9533A5;
+ --purple-dark:#7d2a8b;
+ --purple-deep:#5e1a6b;
+ --ink:#2a0f31;
+ --tint:#f6ecf8;
+ --tint-2:#ecd6f0;
+ --bg:#ffffff;
+ --line:#e5cfe9;
+ --red:#b3261e;
+ --amber:#8a5a00;
+ --green:#1d6b3a;
+ --font:var(--font-jakarta),"Plus Jakarta Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;}
+.rd *,.rd *::before,.rd *::after{box-sizing:inherit}
+.rd{margin:0;background:var(--bg);color:var(--ink);font-family:var(--font);font-size:17px;line-height:1.65;-webkit-font-smoothing:antialiased}
+.rd a{color:inherit;text-decoration:none}
+.rd a:focus-visible,.rd button:focus-visible,.rd select:focus-visible,.rd input:focus-visible,.rd textarea:focus-visible,.rd summary:focus-visible{outline:3px solid var(--purple);outline-offset:3px;border-radius:8px}
+.rd h1,.rd h2,.rd h3,.rd h4{margin:0;font-weight:800;letter-spacing:-.025em;line-height:1.1}
+.rd p{margin:0}
+.rd img{max-width:100%}
+.rd .wrap{max-width:1200px;margin:0 auto;padding:0 32px}
+@media (max-width:640px){
+.rd .wrap{padding:0 20px}
+}
+.rd section{padding:104px 0}
+@media (max-width:768px){
+.rd section{padding:72px 0}
+}
+.rd .pt0{padding-top:0}
+.rd .btn{display:inline-flex;align-items:center;justify-content:center;padding:15px 28px;border-radius:999px;font-weight:700;font-size:1rem;border:2px solid var(--purple);transition:background .2s,color .2s;cursor:pointer;font-family:inherit}
+.rd .btn-solid{background:var(--purple);color:#fff}
+.rd .btn-solid:hover{background:var(--purple-dark);border-color:var(--purple-dark)}
+.rd .btn-line{color:var(--purple-deep);background:transparent}
+.rd .btn-line:hover{background:var(--tint)}
+.rd .btn-white{background:#fff;color:var(--purple);border-color:#fff}
+.rd .btn-white:hover{background:var(--tint)}
+.rd .btn-ghost-white{border-color:#fff;color:#fff;background:transparent}
+.rd .btn-ghost-white:hover{background:rgba(255,255,255,.12)}
+.rd .ctas{display:flex;gap:14px;flex-wrap:wrap}
+.rd .h2{font-size:clamp(2rem,4vw,3rem)}
+.rd .h2 span,.rd .phero h1 span{color:inherit}
+.rd .lede{font-size:1.15rem;line-height:1.7;max-width:660px}
+.rd .center{text-align:center}
+.rd .center .lede{margin:18px auto 0}
+.rd .band{background:var(--tint)}
+.rd .ph{display:flex;align-items:flex-end;border-radius:24px;overflow:hidden;background:
+ radial-gradient(circle at 25% 25%,rgba(255,255,255,.35),transparent 50%),
+ linear-gradient(140deg,#b75cc6,#5e1a6b);color:#fff}
+.rd .ph span{padding:18px 22px;font-weight:600;line-height:1.45}
+.rd .card{background:var(--bg);border:1px solid var(--line);border-radius:24px;padding:32px}
+@media (max-width:640px){
+.rd .card{padding:24px}
+}
+.rd .grid2{display:grid;grid-template-columns:1fr 1fr;gap:24px}
+.rd .grid3{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}
+@media (max-width:900px){
+.rd .grid3{grid-template-columns:1fr}
+}
+@media (max-width:760px){
+.rd .grid2{grid-template-columns:1fr}
+}
+.rd .mt48{margin-top:48px}
+.rd .mt56{margin-top:56px}
+.rd .mt24{margin-top:24px}
+.rd .icon{width:60px;height:60px;border-radius:18px;background:var(--tint-2);display:grid;place-items:center;margin-bottom:22px}
+.rd .tag{display:inline-block;font-size:.85rem;font-weight:700;padding:5px 12px;border-radius:999px;background:var(--tint-2);color:var(--purple-deep)}
+.rd .say{margin-top:16px;background:var(--tint);border-radius:14px;padding:14px 16px;font-weight:700;line-height:1.5}
+.rd .band .say{background:var(--bg)}
+.rd-hdr{position:sticky;top:env(safe-area-inset-top,0px);z-index:40;background:rgba(255,255,255,.94);backdrop-filter:blur(12px);border-bottom:1px solid var(--line)}
+.rd .nav{display:flex;align-items:center;justify-content:space-between;height:76px}
+.rd .logo{display:flex;align-items:center;gap:10px;font-weight:800;font-size:1.35rem;letter-spacing:-.02em}
+.rd .mark{width:36px;height:36px;border-radius:11px;background:var(--purple);display:grid;place-items:center}
+.rd .logo-img{height:46px;width:auto;display:block}
+.rd-ftr .logo-img{height:56px}
+.rd .links{display:flex;gap:6px;align-items:center;font-weight:600;font-size:.98rem;list-style:none;margin:0;padding:0}
+.rd .links>li{position:relative}
+.rd .links>li>a{display:block;padding:9px 14px;border-radius:999px}
+.rd .links>li>a:hover,.rd .links>li>a.active{color:var(--purple);background:var(--tint)}
+.rd .drop{position:absolute;top:100%;left:0;min-width:230px;padding:10px;background:#fff;border:1px solid var(--line);border-radius:16px;box-shadow:0 20px 40px -20px rgba(42,15,49,.3);display:none;flex-direction:column}
+.rd .links>li:hover .drop,.rd .links>li:focus-within .drop{display:flex}
+.rd .drop a{padding:10px 12px;border-radius:10px}
+.rd .drop a:hover{background:var(--tint);color:var(--purple)}
+.rd .links .btn{margin-left:10px;padding:11px 22px}
+.rd .burger{display:none;background:none;border:0;color:var(--ink);cursor:pointer;padding:6px}
+@media (max-width:980px){
+.rd .links{display:none}
+.rd .burger{display:block}
+.rd-hdr.open .links{display:flex;flex-direction:column;align-items:stretch;gap:2px;position:absolute;top:76px;left:0;right:0;background:#fff;padding:14px 20px 24px;border-bottom:1px solid var(--line);max-height:calc(100vh - 76px);overflow:auto}
+.rd-hdr.open .drop{display:flex;position:static;border:0;box-shadow:none;padding:0 0 6px 14px}
+.rd .links .btn{margin:10px 0 0}
+}
+.rd .phero{padding:96px 0 88px;background:linear-gradient(180deg,var(--tint) 0%,var(--bg) 100%)}
+.rd .phero h1{font-size:clamp(2.6rem,5.4vw,4.2rem);max-width:900px}
+.rd .phero p{margin-top:24px;font-size:1.2rem;max-width:660px;line-height:1.7}
+.rd .phero .ctas{margin-top:32px}
+@media (max-width:768px){
+.rd .phero{padding:64px 0 56px}
+}
+.rd .hero{padding:88px 0 96px;background:linear-gradient(180deg,var(--tint) 0%,var(--bg) 100%);overflow:hidden}
+.rd .hero-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:56px;align-items:center}
+@media (max-width:960px){
+.rd .hero-grid{grid-template-columns:1fr}
+}
+.rd .hero h1{font-size:clamp(2.6rem,5.6vw,4.4rem)}
+.rd .rotator{display:block;color:var(--purple);min-height:2.3em}
+@media (min-width:961px){
+.rd .rotator{min-height:1.15em}
+}
+.rd .rotator span{display:inline-block;transition:opacity .35s,transform .35s}
+.rd .rotator span.out{opacity:0;transform:translateY(12px)}
+.rd .hero p{margin:26px 0 34px;font-size:1.2rem;max-width:540px}
+.rd .hero-art{width:100%;height:auto;max-width:600px;justify-self:center}
+.rd .hero-art .hb-card{animation:rd-hb-float 6s ease-in-out infinite;transform-box:fill-box}
+.rd .hero-art .hb-c2{animation-delay:-2s}
+.rd .hero-art .hb-c3{animation-delay:-4s}
+@keyframes rd-hb-float{0%,100%{transform:translateY(0)}50%{transform:translateY(-8px)}}
+@media (prefers-reduced-motion:reduce){
+.rd .hero-art .hb-card{animation:none}
+}
+.rd .strip{padding:40px 0;border-block:1px solid var(--line)}
+.rd .strip-in{display:flex;align-items:center;gap:40px;flex-wrap:wrap;justify-content:space-between}
+.rd .strip h4{font-size:1rem;font-weight:700;letter-spacing:0}
+.rd .sources{display:flex;gap:36px;flex-wrap:wrap;font-weight:800;font-size:1.05rem;color:var(--purple-deep)}
+.rd .what{display:grid;grid-template-columns:1fr 1fr;gap:72px;align-items:center}
+@media (max-width:960px){
+.rd .what{grid-template-columns:1fr;gap:48px}
+}
+.rd .what .lede{margin:22px 0 32px}
+.rd .phone-stage{display:flex;justify-content:center;padding:20px 0}
+.rd .phone{width:280px;aspect-ratio:9/18;border-radius:44px;background:var(--ink);padding:12px;box-shadow:0 30px 60px -20px rgba(94,26,107,.45)}
+.rd .screen{height:100%;border-radius:34px;background:linear-gradient(170deg,#c67bd3,#6d2279);padding:56px 14px 14px;display:flex;flex-direction:column;gap:10px}
+.rd .clock{color:#fff;text-align:center;font-weight:700;font-size:3rem;letter-spacing:-.03em;margin-bottom:18px}
+.rd .notif{background:rgba(255,255,255,.95);color:#2a0f31;border-radius:18px;padding:12px 14px;font-size:.86rem;line-height:1.4;opacity:0;transform:translateY(16px);transition:opacity .5s,transform .5s}
+.rd .notif.show{opacity:1;transform:none}
+.rd .notif b{display:flex;justify-content:space-between;font-size:.8rem;margin-bottom:3px}
+.rd .notif b i{font-style:normal;font-weight:500}
+.rd .rows{display:flex;flex-direction:column;gap:72px;margin-top:72px}
+.rd .row{display:grid;grid-template-columns:1fr 1fr;gap:72px;align-items:center}
+.rd .row:nth-child(even) .row-art{order:2}
+@media (max-width:860px){
+.rd .row{grid-template-columns:1fr;gap:28px}
+.rd .row:nth-child(even) .row-art{order:0}
+}
+.rd .row-art{background:var(--tint);border-radius:28px;aspect-ratio:4/3;display:grid;place-items:center;padding:28px}
+.rd .row-art svg{width:100%;max-width:340px;height:auto}
+.rd .big{font-size:clamp(3rem,6vw,4.6rem);font-weight:800;color:var(--purple);letter-spacing:-.04em;line-height:1}
+.rd .row h3{font-size:1.5rem;margin:14px 0}
+.rd .row p{font-size:1.1rem;line-height:1.75}
+.rd .row cite{display:block;margin-top:14px;font-style:normal;font-weight:600;color:var(--purple-deep)}
+.rd .pcard{background:var(--bg);border-radius:24px;padding:36px 30px}
+.rd .pcard h3{font-size:1.5rem;margin-bottom:12px}
+.rd .pcard p{font-size:1.05rem;line-height:1.7}
+.rd .tabs{display:inline-flex;background:var(--tint);border-radius:999px;padding:6px;gap:4px;flex-wrap:wrap;justify-content:center}
+.rd .tabs button{border:0;background:transparent;font:inherit;font-weight:700;color:var(--ink);padding:11px 22px;border-radius:999px;cursor:pointer}
+.rd .tabs button[aria-selected="true"]{background:var(--purple);color:#fff}
+.rd .story{display:grid;grid-template-columns:.8fr 1.2fr;gap:56px;align-items:start;margin-top:48px;text-align:left}
+@media (max-width:900px){
+.rd .story{grid-template-columns:1fr;gap:28px}
+}
+.rd .story-meta{background:var(--purple);color:#fff;border-radius:28px;padding:36px}
+.rd .story-meta .n{font-size:4rem;font-weight:800;line-height:1;letter-spacing:-.04em}
+.rd .story-meta h3{font-size:1.8rem;margin-top:14px}
+.rd .story-meta p{margin-top:12px;font-weight:600}
+.rd .story-body p{font-size:1.1rem;line-height:1.8;margin-bottom:16px}
+.rd .pull{margin-top:24px;border-left:4px solid var(--purple);padding:6px 0 6px 22px;font-size:1.2rem;font-weight:700;line-height:1.55}
+.rd .pull cite{display:block;font-style:normal;font-weight:600;font-size:1rem;margin-top:10px;color:var(--purple-deep)}
+.rd [hidden]{display:none!important}
+.rd .plan{display:grid;grid-template-columns:.9fr 1.1fr;gap:64px;align-items:start}
+@media (max-width:900px){
+.rd .plan{grid-template-columns:1fr;gap:36px}
+}
+.rd .plan .lede{margin-top:18px}
+.rd .plan-card{border:2px solid var(--purple);border-radius:28px;padding:40px;background:var(--bg)}
+@media (max-width:640px){
+.rd .plan-card{padding:28px}
+}
+.rd .plan-head{display:flex;justify-content:space-between;align-items:baseline;flex-wrap:wrap;gap:10px;padding-bottom:22px;border-bottom:1px solid var(--line);margin-bottom:24px}
+.rd .plan-head h3{font-size:1.6rem}
+.rd .price{font-size:2.4rem;font-weight:800;color:var(--purple);letter-spacing:-.03em}
+.rd .checks{list-style:none;padding:0;margin:0;display:grid;grid-template-columns:1fr 1fr;gap:16px 28px}
+@media (max-width:640px){
+.rd .checks{grid-template-columns:1fr}
+}
+.rd .checks li{display:flex;gap:12px;font-weight:600;line-height:1.45}
+.rd .checks svg{flex:0 0 22px;margin-top:1px}
+.rd .offer{display:grid;grid-template-columns:1fr 1fr;gap:18px;margin-top:28px}
+@media (max-width:640px){
+.rd .offer{grid-template-columns:1fr}
+}
+.rd .offer div{background:var(--tint);border-radius:18px;padding:20px}
+.rd .offer h4{font-size:1.05rem;letter-spacing:-.01em;margin-bottom:6px}
+.rd .offer p{font-size:.98rem;line-height:1.6}
+.rd .cta{background:var(--purple);color:#fff;border-radius:36px;padding:72px 64px;display:grid;grid-template-columns:1.3fr .7fr;gap:40px;align-items:center}
+@media (max-width:860px){
+.rd .cta{grid-template-columns:1fr;padding:48px 28px}
+}
+.rd .cta h2{font-size:clamp(2rem,3.6vw,2.8rem)}
+.rd .cta p{margin:18px 0 30px;font-size:1.15rem;max-width:560px}
+.rd .cta svg{width:100%;max-width:260px;justify-self:center}
+.rd .split{display:grid;grid-template-columns:1fr 1fr;gap:64px;align-items:center}
+@media (max-width:900px){
+.rd .split{grid-template-columns:1fr;gap:36px}
+}
+.rd .split .ph{aspect-ratio:5/4}
+.rd .split p{margin:18px 0;font-size:1.1rem;line-height:1.75}
+.rd .chips{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:30px}
+.rd .chips span{background:var(--tint);border-radius:999px;padding:8px 16px;font-weight:700;font-size:.95rem}
+.rd .why-done{margin-top:56px;font-size:clamp(1.4rem,2.6vw,2rem);font-weight:800;letter-spacing:-.02em;text-align:center}
+.rd .why-done strong{color:var(--purple)}
+.rd .mgrid{display:grid;grid-template-columns:1.1fr 1fr;gap:64px;align-items:center;margin-top:56px}
+@media (max-width:960px){
+.rd .mgrid{grid-template-columns:1fr;gap:36px}
+}
+.rd .mgrid .ph{aspect-ratio:618/1080;max-height:640px}
+@media (max-width:960px){
+.rd .mgrid .ph{aspect-ratio:4/3}
+}
+.rd .mlist{display:flex;flex-direction:column;gap:20px}
+.rd .mitem{display:grid;grid-template-columns:60px 1fr;gap:20px;align-items:start;background:var(--bg);border-radius:24px;padding:28px}
+.rd .mitem .icon{margin:0}
+.rd .mitem h3{font-size:1.5rem;margin-bottom:8px}
+.rd .timeline{position:relative;max-width:860px;margin:56px auto 0;display:flex;flex-direction:column;gap:28px}
+.rd .tl{display:grid;grid-template-columns:88px 1fr;gap:28px}
+@media (max-width:640px){
+.rd .tl{grid-template-columns:1fr;gap:14px}
+}
+.rd .tl-n{width:88px;height:88px;border-radius:24px;background:var(--purple);color:#fff;display:grid;place-items:center;font-weight:800;font-size:1.8rem}
+.rd .tl .card h3{font-size:1.6rem;margin-bottom:14px}
+.rd .tl .card p{font-size:1.05rem;line-height:1.8;margin-bottom:12px}
+.rd .quote-band{background:var(--purple-deep);color:#fff;border-radius:36px;padding:72px 64px;text-align:center}
+@media (max-width:768px){
+.rd .quote-band{padding:48px 28px}
+}
+.rd .quote-band p{font-size:clamp(1.5rem,3vw,2.2rem);font-weight:700;letter-spacing:-.02em;line-height:1.35;max-width:880px;margin:0 auto}
+.rd .quote-band cite{display:block;margin-top:22px;font-style:normal;font-weight:600}
+.rd .carousel{position:relative;border-radius:24px;overflow:hidden}
+.rd .slides{display:flex;transition:transform .6s ease}
+.rd .slides .ph{flex:0 0 100%;height:clamp(300px,42vw,520px);border-radius:0}
+.rd .slides img{flex:0 0 100%;width:100%;height:clamp(300px,46vw,560px);object-fit:cover;object-position:center 55%;display:block}
+.rd .slides.berk img{object-position:center 72%}
+.rd .mphoto{width:100%;aspect-ratio:4/3;object-fit:cover;object-position:center 70%;border-radius:24px;display:block}
+.rd .dots{position:absolute;bottom:18px;right:20px;display:flex;gap:8px}
+.rd .dots button{width:11px;height:11px;border-radius:50%;border:2px solid #fff;background:transparent;padding:0;cursor:pointer}
+.rd .dots button[aria-current="true"]{background:#fff}
+.rd .video{aspect-ratio:16/9;align-items:center;justify-content:center;flex-direction:column;text-align:center}
+.rd .play{width:68px;height:68px;border-radius:50%;background:#fff;display:grid;place-items:center;margin-bottom:6px}
+.rd .aisteps{display:grid;grid-template-columns:repeat(4,1fr);gap:24px}
+@media (max-width:1000px){
+.rd .aisteps{grid-template-columns:1fr 1fr}
+}
+@media (max-width:560px){
+.rd .aisteps{grid-template-columns:1fr}
+}
+.rd .aistep{background:var(--bg);border-radius:24px;padding:18px 18px 28px}
+.rd .aistep-art{background:var(--tint);border-radius:18px;aspect-ratio:24/17;display:grid;place-items:center;margin-bottom:22px}
+.rd .aistep-art svg{width:100%;height:auto}
+.rd .aistep h3{font-size:1.2rem;padding:0 8px;margin-bottom:8px;letter-spacing:-.015em}
+.rd .aistep p{padding:0 8px;line-height:1.6;font-size:.98rem}
+.rd .ai-src{text-align:center;margin-top:24px;font-weight:600;color:var(--purple-deep);font-size:.95rem}
+.rd .ai-bottom{display:grid;grid-template-columns:.85fr 1.15fr;gap:24px;margin-top:48px;align-items:stretch}
+@media (max-width:900px){
+.rd .ai-bottom{grid-template-columns:1fr}
+}
+.rd .ai-save{background:var(--bg);border-radius:28px;padding:40px;display:flex;flex-direction:column;align-items:flex-start;gap:12px}
+.rd .ai-save h3{font-size:1.5rem}
+.rd .ai-save p{line-height:1.7;flex:1}
+.rd .ai-tips h3{font-size:1.6rem}
+.rd .checks.one{grid-template-columns:1fr}
+.rd .checks.one li{font-weight:500}
+.rd .a-hero{padding-bottom:40px}
+.rd .a-hero h1{margin:0 auto}
+.rd .scroll-cue{width:26px;height:42px;border:2px solid var(--purple);border-radius:14px;margin:40px auto 0;position:relative}
+.rd .scroll-cue span{position:absolute;left:50%;top:8px;width:4px;height:8px;margin-left:-2px;border-radius:2px;background:var(--purple);animation:rd-cue 1.6s infinite}
+@keyframes rd-cue{0%{opacity:0;transform:translateY(0)}30%{opacity:1}100%{opacity:0;transform:translateY(14px)}}
+.rd .zoom{height:280vh;padding:0;position:relative}
+.rd .zoom-sticky{position:sticky;top:calc(env(safe-area-inset-top,0px) + 76px);height:calc(100vh - 76px);height:calc(100svh - 76px);overflow:hidden}
+.rd .zoom-frame{position:absolute;inset:0;--p:0;clip-path:inset(calc((1 - var(--p)) * 14%) calc((1 - var(--p)) * 22%) round calc((1 - var(--p)) * 36px));will-change:clip-path}
+.rd .zoom-imgs{position:absolute;inset:0;transform:scale(calc(1.18 - var(--p) * .18));will-change:transform}
+.rd .zoom-imgs img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity 1.1s ease}
+.rd .zoom-imgs img.on{opacity:1;animation:rd-kb 6s ease-out forwards}
+@keyframes rd-kb{from{transform:scale(1.06)}to{transform:scale(1)}}
+.rd .zoom-shade{position:absolute;inset:0;background:linear-gradient(180deg,rgba(42,15,49,0) 40%,rgba(42,15,49,.75) 100%);opacity:calc(var(--p) * 1.2)}
+.rd .zoom-copy{position:absolute;left:0;right:0;bottom:0;padding:0 max(32px,calc((100% - 1136px)/2)) 64px;color:#fff;opacity:clamp(0,calc((var(--p) - .6) * 3),1);transform:translateY(calc((1 - clamp(0,calc((var(--p) - .6) * 3),1)) * 30px))}
+.rd .zoom-copy h2{font-size:clamp(2.2rem,5vw,4rem)}
+.rd .zoom-copy p{margin-top:14px;font-size:1.15rem;max-width:540px;line-height:1.6}
+.rd .zoom-ctrl{position:absolute;right:max(32px,calc((100% - 1136px)/2));bottom:64px;display:flex;align-items:center;gap:12px;color:#fff;opacity:clamp(0,calc((var(--p) - .6) * 3),1)}
+.rd .zoom-count{font-weight:700;font-variant-numeric:tabular-nums}
+.rd .zoom-ctrl button{width:40px;height:40px;border-radius:50%;border:2px solid #fff;background:rgba(255,255,255,.12);color:#fff;display:grid;place-items:center;cursor:pointer}
+@media (max-width:760px){
+.rd .zoom-copy{padding:0 20px 96px}
+.rd .zoom-ctrl{right:20px;bottom:36px}
+}
+@media (prefers-reduced-motion:reduce){
+.rd .zoom{height:auto}
+.rd .zoom-sticky{position:relative;top:0;height:70vh}
+.rd .zoom-frame{--p:1!important}
+.rd .zoom-imgs img{transition:none}
+.rd .zoom-imgs img.on{animation:none}
+.rd .scroll-cue span{animation:none}
+}
+.rd .pillar-lg{padding:8px 4px}
+.rd .pillar-lg h3{font-size:1.7rem;margin-bottom:10px}
+.rd .pillar-lg p{font-size:1.08rem;line-height:1.7}
+.rd .founder{display:grid;grid-template-columns:.9fr 1.1fr;gap:64px;align-items:start}
+@media (max-width:900px){
+.rd .founder{grid-template-columns:1fr;gap:36px}
+}
+.rd .founder-side{position:sticky;top:120px}
+@media (max-width:900px){
+.rd .founder-side{position:static}
+}
+.rd .founder-side .lede{margin-top:18px}
+.rd .strikes{display:flex;flex-direction:column;gap:20px}
+.rd .strike-card{background:var(--bg);border-radius:24px;padding:32px;opacity:.35;transform:translateY(24px);transition:opacity .6s,transform .6s}
+.rd .strike-card.in{opacity:1;transform:none}
+@media (prefers-reduced-motion:reduce){
+.rd .strike-card{opacity:1;transform:none;transition:none}
+}
+.rd .strike-top{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-bottom:14px}
+.rd .strike-n{font-size:2.6rem;font-weight:800;color:var(--purple);letter-spacing:-.04em;line-height:1}
+.rd .strike-card h3{font-size:1.5rem;margin-bottom:10px}
+.rd .strike-card p{font-size:1.05rem;line-height:1.75}
+.rd .provide4{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}
+@media (max-width:1000px){
+.rd .provide4{grid-template-columns:1fr 1fr}
+}
+@media (max-width:560px){
+.rd .provide4{grid-template-columns:1fr}
+}
+.rd .provide4 .pcard{padding:30px 26px}
+.rd .provide4 .pcard h3{font-size:1.3rem}
+.rd .provide4 .pcard p{font-size:1rem}
+.rd .filters{margin-top:36px}
+.rd .team{display:grid;grid-template-columns:repeat(3,1fr);gap:24px;margin-top:48px}
+@media (max-width:1000px){
+.rd .team{grid-template-columns:1fr 1fr}
+}
+@media (max-width:640px){
+.rd .team{grid-template-columns:1fr}
+}
+.rd .member{display:flex;flex-direction:column;gap:14px}
+.rd .avatar{width:84px;height:84px;border-radius:24px;background:var(--tint-2);color:var(--purple-deep);display:grid;place-items:center;font-weight:800;font-size:1.6rem}
+.rd .member h3{font-size:1.3rem;letter-spacing:-.015em}
+.rd .member .role{font-weight:700;color:var(--purple)}
+.rd .member .school{font-weight:600;font-size:.95rem}
+.rd .member p.bio{font-size:1rem;line-height:1.65}
+.rd .member button.more{align-self:flex-start;background:none;border:0;padding:0;font:inherit;font-weight:700;color:var(--purple);cursor:pointer}
+.rd .member .ln{font-weight:700;color:var(--purple);font-size:.95rem}
+.rd .study{display:grid;grid-template-columns:260px 1fr;gap:40px}
+@media (max-width:860px){
+.rd .study{grid-template-columns:1fr;gap:20px}
+}
+.rd .study-meta{display:flex;flex-direction:column;gap:10px;font-weight:600}
+.rd .study-meta .n{font-size:3.4rem;font-weight:800;color:var(--purple);letter-spacing:-.04em;line-height:1}
+.rd .study h3{font-size:1.6rem;margin-bottom:14px}
+.rd .study p{font-size:1.05rem;line-height:1.8;margin-bottom:14px}
+.rd .tags{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}
+.rd .statset{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:22px}
+@media (max-width:760px){
+.rd .statset{grid-template-columns:1fr}
+}
+.rd .statset .card{padding:28px}
+.rd .statset .big{font-size:clamp(2.4rem,4vw,3.2rem)}
+.rd .statset p{margin-top:12px;line-height:1.6}
+.rd .cites .card h4{font-size:1rem;letter-spacing:0;color:var(--purple);margin-bottom:10px}
+.rd .cites .card p{line-height:1.7}
+.rd .cites .card p+p{margin-top:10px}
+.rd .projects{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}
+@media (max-width:1000px){
+.rd .projects{grid-template-columns:1fr;max-width:640px;margin:0 auto}
+}
+.rd .proj{display:flex;flex-direction:column;gap:16px;background:var(--bg);border:1px solid var(--line);border-radius:24px;padding:32px;transition:border-color .2s,box-shadow .2s}
+.rd .proj:hover{border-color:var(--purple);box-shadow:0 24px 48px -28px rgba(94,26,107,.45)}
+.rd .proj-head{display:flex;justify-content:space-between;align-items:flex-start}
+.rd .proj-head .icon{margin:0}
+.rd .proj h3{font-size:1.6rem}
+.rd .proj-desc{line-height:1.7;flex:1}
+.rd .proj-meta{display:flex;flex-direction:column;gap:14px;padding-top:18px;border-top:1px solid var(--line)}
+.rd .proj-row{display:grid;grid-template-columns:22px 1fr;gap:12px;align-items:start;color:var(--purple-deep)}
+.rd .proj-row svg{margin-top:3px}
+.rd .proj-row b{color:var(--ink)}
+.rd .chips-sm{display:flex;flex-wrap:wrap;gap:6px}
+.rd .chips-sm span{background:var(--tint);color:var(--ink);border-radius:999px;padding:4px 12px;font-size:.9rem;font-weight:600}
+.rd .seats{display:flex;gap:4px;margin-top:8px}
+.rd .seats i{width:14px;height:14px;border-radius:50%;background:var(--tint-2)}
+.rd .seats i.f{background:var(--purple)}
+.rd .seats i.r{background:#c98fd4}
+.rd .proj-btn{margin-top:6px;align-self:stretch}
+.rd .notlist{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:32px}
+@media (max-width:760px){
+.rd .notlist{grid-template-columns:1fr}
+}
+.rd .notlist .card{padding:26px}
+.rd .notlist b{display:block;font-size:1.15rem;margin-bottom:6px}
+.rd .explorer{display:grid;grid-template-columns:1.15fr .85fr;gap:32px;margin-top:48px;align-items:start}
+@media (max-width:960px){
+.rd .explorer{grid-template-columns:1fr}
+}
+.rd .stage{position:relative;border-radius:24px;overflow:hidden;background:var(--tint);border:1px solid var(--line)}
+.rd .stage svg{display:block;width:100%;height:auto}
+.rd .pin{position:absolute;transform:translate(-50%,-50%);width:36px;height:36px;border-radius:50%;border:3px solid #fff;background:var(--purple);color:#fff;font-weight:800;font-size:.95rem;cursor:pointer;box-shadow:0 6px 16px -4px rgba(42,15,49,.5);font-family:inherit}
+.rd .pin[aria-pressed="true"]{background:var(--ink);transform:translate(-50%,-50%) scale(1.15)}
+.rd .panel{background:var(--bg);border:1px solid var(--line);border-radius:24px;padding:32px;min-height:320px}
+.rd .panel h3{font-size:1.5rem;margin:12px 0}
+.rd .panel p{line-height:1.75}
+.rd .panel .empty{display:flex;flex-direction:column;justify-content:center;align-items:flex-start;gap:12px;min-height:250px;font-weight:600;font-size:1.1rem}
+.rd .sev-easy{background:#e3f3e8;color:var(--green)}
+.rd .sev-watch{background:#fbefd5;color:var(--amber)}
+.rd .sev-red{background:#fbe1df;color:var(--red)}
+.rd .sev-know{background:var(--tint-2);color:var(--purple-deep)}
+.rd .legend{display:flex;gap:10px;flex-wrap:wrap;margin-top:16px}
+.rd .where .card h3{font-size:1.35rem;margin-bottom:12px}
+.rd .where .card p{line-height:1.7}
+.rd .where .card p+p{margin-top:10px}
+.rd .brands{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-top:40px}
+@media (max-width:760px){
+.rd .brands{grid-template-columns:1fr 1fr}
+}
+.rd .brands a{border:1px solid var(--line);border-radius:18px;padding:22px;font-weight:800;font-size:1.1rem;text-align:center;background:var(--bg);transition:border-color .2s,color .2s}
+.rd .brands a:hover{border-color:var(--purple);color:var(--purple)}
+.rd .acc{display:flex;flex-direction:column;gap:14px;margin-top:48px;max-width:900px}
+.rd details{background:var(--bg);border:1px solid var(--line);border-radius:20px;padding:0 28px}
+.rd summary{list-style:none;cursor:pointer;display:flex;justify-content:space-between;align-items:center;gap:16px;padding:24px 0;font-weight:800;font-size:1.2rem;letter-spacing:-.015em}
+.rd summary::-webkit-details-marker{display:none}
+.rd summary::after{content:"+";font-size:1.6rem;font-weight:500;color:var(--purple);line-height:1}
+.rd details[open] summary::after{content:"–"}
+.rd details .body{padding:0 0 26px;line-height:1.75}
+.rd details ul{margin:10px 0 0;padding-left:20px;display:flex;flex-direction:column;gap:8px}
+.rd .road{display:grid;grid-template-columns:repeat(6,1fr);gap:0;margin-top:56px;position:relative}
+.rd .road::before{content:"";position:absolute;top:28px;left:8%;right:8%;height:6px;background:repeating-linear-gradient(90deg,var(--purple) 0 22px,transparent 22px 36px);border-radius:3px}
+.rd .stop{position:relative;display:flex;flex-direction:column;align-items:center;gap:14px;text-align:center;background:none;border:0;font:inherit;color:var(--ink);cursor:pointer;padding:0 6px}
+.rd .stop .dot{width:62px;height:62px;border-radius:50%;background:#fff;border:4px solid var(--purple);display:grid;place-items:center;font-weight:800;font-size:1.2rem;color:var(--purple);transition:background .2s,color .2s}
+.rd .stop[aria-pressed="true"] .dot{background:var(--purple);color:#fff}
+.rd .stop b{font-size:.98rem;line-height:1.35}
+@media (max-width:860px){
+.rd .road{grid-template-columns:1fr;gap:14px}
+.rd .road::before{display:none}
+.rd .stop{flex-direction:row;text-align:left}
+.rd .stop .dot{flex:0 0 52px;width:52px;height:52px}
+}
+.rd .road-panel{margin-top:32px;max-width:760px;margin-left:auto;margin-right:auto}
+.rd .alert{margin-top:32px;border-left:4px solid var(--purple);background:var(--tint);border-radius:0 18px 18px 0;padding:22px 26px;line-height:1.7}
+.rd .alert b{display:block;margin-bottom:4px}
+.rd .flags{display:flex;flex-wrap:wrap;gap:12px;margin-top:40px}
+.rd .flags button{display:flex;align-items:center;gap:12px;border:1px solid var(--line);background:#fff;border-radius:999px;padding:10px 20px 10px 10px;font:inherit;font-weight:700;color:var(--ink);cursor:pointer}
+.rd .flags button span{width:32px;height:32px;border-radius:50%;background:var(--tint-2);color:var(--purple);display:grid;place-items:center;font-weight:800}
+.rd .flags button[aria-pressed="true"]{border-color:var(--purple);background:var(--purple);color:#fff}
+.rd .flags button[aria-pressed="true"] span{background:#fff}
+.rd .flag-panel{margin-top:24px}
+.rd .law-h{font-size:1.6rem;margin:56px 0 20px}
+.rd .law .card h3{font-size:1.3rem;margin:12px 0}
+.rd .law .card p{line-height:1.7}
+.rd .fields{display:flex;flex-wrap:wrap;gap:10px;margin-bottom:18px}
+.rd .fields button{border:1px solid var(--line);background:#fff;border-radius:999px;padding:9px 16px;font:inherit;font-weight:700;color:var(--ink);cursor:pointer}
+.rd .fields button[aria-pressed="true"]{background:var(--purple);border-color:var(--purple);color:#fff}
+.rd .title-doc{position:relative;background:#fbeef3;border:2px solid #e3b6c7;border-radius:12px;padding:22px;font-size:.8rem;line-height:1.4;color:#4a1d2e}
+.rd .title-doc .zone{display:block;width:100%;text-align:left;border:2px dashed transparent;border-radius:8px;padding:10px;background:none;font:inherit;color:inherit;cursor:pointer;margin-bottom:6px}
+.rd .title-doc .zone:hover,.rd .title-doc .zone[aria-pressed="true"]{border-color:var(--purple);background:rgba(149,51,165,.08)}
+.rd .title-doc .zone b{display:block;font-size:.72rem;letter-spacing:.02em;margin-bottom:4px}
+.rd .title-doc .hd{text-align:center;font-weight:800;font-size:1rem;margin-bottom:10px;letter-spacing:.02em}
+.rd .line-fake{height:8px;border-radius:4px;background:#e8c3d2;margin:4px 0}
+.rd .flip-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:40px}
+@media (max-width:860px){
+.rd .flip-grid{grid-template-columns:1fr}
+}
+.rd .flip{perspective:1000px;background:none;border:0;padding:0;font:inherit;color:inherit;cursor:pointer;text-align:left;min-height:220px}
+.rd .flip-in{position:relative;height:100%;min-height:220px;transition:transform .6s;transform-style:preserve-3d}
+.rd .flip[aria-pressed="true"] .flip-in{transform:rotateY(180deg)}
+.rd .face{position:absolute;inset:0;border-radius:24px;padding:28px;backface-visibility:hidden;-webkit-backface-visibility:hidden;display:flex;flex-direction:column;justify-content:space-between}
+.rd .front{background:var(--purple);color:#fff}
+.rd .front .n{font-size:3rem;font-weight:800;line-height:1}
+.rd .front b{font-size:1.3rem;line-height:1.3}
+.rd .back{background:#fff;border:2px solid var(--purple);transform:rotateY(180deg);justify-content:center;font-size:1.05rem;line-height:1.7}
+@media (prefers-reduced-motion:reduce){
+.rd .flip-in{transition:none}
+}
+.rd .rc-legend{display:flex;gap:22px;flex-wrap:wrap;justify-content:center;margin-top:32px;font-weight:600}
+.rd .rc-legend span{display:flex;align-items:center;gap:8px}
+.rd .dot{width:12px;height:12px;border-radius:50%;display:inline-block;flex:0 0 12px}
+.rd .dot.req{background:#1d6b3a}
+.rd .dot.neg{background:#9533A5}
+.rd .dot.opt{background:#8a5a00}
+.rd .dot.red{background:#b3261e}
+.rd .rc-grid{display:grid;grid-template-columns:1fr 1fr;gap:32px;margin-top:40px;align-items:start}
+@media (max-width:900px){
+.rd .rc-grid{grid-template-columns:1fr}
+}
+.rd .receipt{background:#fff;border:1px solid var(--line);border-radius:8px 8px 0 0;padding:28px 26px 30px;position:relative;box-shadow:0 24px 48px -30px rgba(42,15,49,.4);
+ -webkit-mask:radial-gradient(circle 9px at 50% 100%,transparent 98%,#000) 0 0/22px 100% repeat-x;mask:radial-gradient(circle 9px at 50% 100%,transparent 98%,#000) 0 0/22px 100% repeat-x;padding-bottom:44px}
+.rd .rc-head{display:flex;justify-content:space-between;align-items:baseline;flex-wrap:wrap;gap:6px;padding-bottom:16px;border-bottom:2px dashed var(--line);margin-bottom:8px}
+.rd .rc-head b{font-size:1.3rem;letter-spacing:-.02em}
+.rd .rc-head span{font-weight:600;font-size:.92rem;color:var(--purple-deep)}
+.rd .rc-lines{list-style:none;margin:0;padding:0}
+.rd .rc-lines button{width:100%;display:grid;grid-template-columns:14px 1fr auto;gap:12px;align-items:center;padding:12px 10px;margin:0 -10px;width:calc(100% + 20px);border:0;background:none;border-radius:10px;font:inherit;color:var(--ink);text-align:left;cursor:pointer;font-variant-numeric:tabular-nums}
+.rd .rc-lines button:hover{background:var(--tint)}
+.rd .rc-lines button[aria-pressed="true"]{background:var(--tint-2)}
+.rd .rc-lines .amt{font-weight:700}
+.rd .rc-lines li.gone button{opacity:.4}
+.rd .rc-lines li.gone .nm,.rd .rc-lines li.gone .amt{text-decoration:line-through}
+.rd .rc-total{display:flex;justify-content:space-between;align-items:baseline;border-top:2px dashed var(--line);margin-top:10px;padding-top:16px;font-size:1.15rem;font-variant-numeric:tabular-nums}
+.rd .rc-total b{font-size:1.6rem;letter-spacing:-.02em}
+.rd .rc-toggle{display:flex;gap:10px;align-items:center;margin-top:18px;font-weight:600;cursor:pointer}
+.rd .rc-toggle input{width:20px;height:20px;accent-color:var(--purple)}
+.rd .rc-save{margin-top:12px;font-weight:700;color:var(--green)}
+.rd .rc-panel{position:sticky;top:100px}
+.rd .rc-panel .cat{display:inline-flex;align-items:center;gap:8px}
+@media (max-width:900px){
+.rd .rc-panel{position:static}
+}
+.rd .apr{display:grid;grid-template-columns:1.05fr .95fr;gap:24px;align-items:stretch}
+@media (max-width:960px){
+.rd .apr{grid-template-columns:1fr}
+}
+.rd .apr-controls,.rd .apr-results{background:var(--bg);border-radius:28px;padding:36px}
+@media (max-width:640px){
+.rd .apr-controls,.rd .apr-results{padding:26px}
+}
+.rd .apr-label{display:block;font-weight:700;font-size:.95rem;margin-bottom:8px}
+.rd .apr-rate span{font-size:clamp(3rem,6vw,4.4rem);font-weight:800;letter-spacing:-.04em;color:var(--purple);line-height:1;font-variant-numeric:tabular-nums}
+.rd .apr-rate.over span{color:var(--red)}
+.rd .apr-track-wrap{position:relative;margin:26px 0 8px;padding-bottom:44px}
+.rd #aprRate{-webkit-appearance:none;appearance:none;width:100%;height:12px;border-radius:6px;background:linear-gradient(90deg,var(--purple) var(--fill,15%),var(--tint-2) var(--fill,15%));outline:none;margin:0}
+.rd #aprRate::-webkit-slider-thumb{-webkit-appearance:none;width:30px;height:30px;border-radius:50%;background:#fff;border:4px solid var(--purple);cursor:grab;box-shadow:0 4px 12px -2px rgba(42,15,49,.4)}
+.rd #aprRate::-moz-range-thumb{width:24px;height:24px;border-radius:50%;background:#fff;border:4px solid var(--purple);cursor:grab}
+.rd #aprRate:focus-visible{outline:3px solid var(--purple);outline-offset:6px}
+.rd .apr-marks{position:absolute;left:15px;right:15px;top:0;height:100%;pointer-events:none}
+.rd .mk{position:absolute;top:-6px;transform:translateX(-50%);display:flex;flex-direction:column;align-items:center}
+.rd .mk i{width:3px;height:24px;border-radius:2px}
+.rd .mk em{font-style:normal;font-size:.78rem;font-weight:700;white-space:nowrap;margin-top:4px}
+.rd .mk-buy i{background:var(--ink)}
+.rd .mk-buy em{color:var(--ink)}
+.rd .mk-cap i{background:var(--red)}
+.rd .mk-cap em{color:var(--red)}
+.rd .mk-cap{top:-6px}
+.rd .mk.low em{margin-top:22px}
+.rd .apr-scale{display:flex;justify-content:space-between;font-weight:600;font-size:.85rem;position:absolute;left:0;right:0;bottom:0}
+.rd .apr-row{display:flex;flex-wrap:wrap;gap:20px 28px;margin-top:22px}
+@media (max-width:640px){
+.rd .apr-row{grid-template-columns:1fr}
+}
+.rd .seg{display:inline-flex;background:var(--tint);border-radius:999px;padding:4px;gap:2px;flex-wrap:nowrap}
+.rd .seg button{border:0;background:none;font:inherit;font-weight:700;padding:9px 13px;border-radius:999px;cursor:pointer;color:var(--ink);font-size:.92rem;white-space:nowrap}
+.rd .seg button[aria-checked="true"]{background:var(--purple);color:#fff}
+.rd .stepper{display:inline-flex;align-items:center;gap:4px;background:var(--tint);border-radius:999px;padding:4px}
+.rd .stepper button{width:36px;height:36px;border-radius:50%;border:0;background:#fff;font:inherit;font-weight:800;font-size:1.2rem;cursor:pointer;color:var(--purple)}
+.rd .stepper input{width:56px;border:0;background:none;font:inherit;font-weight:800;text-align:right;color:var(--ink);font-size:1.05rem;-moz-appearance:textfield}
+.rd .stepper input::-webkit-inner-spin-button{-webkit-appearance:none}
+.rd .stepper span{font-weight:800;margin-right:8px}
+.rd .apr-hint{margin-top:18px;font-weight:600}
+.rd .apr-big b{display:block;font-size:clamp(2.6rem,5vw,3.6rem);font-weight:800;letter-spacing:-.04em;line-height:1;font-variant-numeric:tabular-nums}
+.rd .apr-split{display:grid;grid-template-columns:1fr 1fr;gap:18px;margin-top:26px;padding-top:22px;border-top:1px solid var(--line)}
+.rd .apr-split b{font-size:1.6rem;font-weight:800;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
+.rd .apr-bar{display:flex;height:18px;border-radius:9px;overflow:hidden;margin-top:26px;background:var(--tint)}
+.rd .apr-bar i{display:block;height:100%;transition:width .25s}
+.rd #barP{background:var(--ink)}
+.rd #barI{background:var(--purple)}
+.rd .apr-bar-key{display:flex;gap:18px;margin-top:10px;font-weight:600;font-size:.92rem}
+.rd .apr-bar-key span{display:flex;align-items:center;gap:6px}
+.rd .apr-bar-key i{width:12px;height:12px;border-radius:3px;display:inline-block}
+.rd .apr-bar-key .k1{background:var(--ink)}
+.rd .apr-bar-key .k2{background:var(--purple)}
+.rd .apr-verdict{margin-top:24px;border-radius:16px;padding:16px 18px;font-weight:600;line-height:1.55;background:var(--tint)}
+.rd .apr-verdict.bad{background:#fbe1df;color:#7a1a14}
+.rd .apr-verdict.ok{background:#e3f3e8;color:#14512b}
+@media (prefers-reduced-motion:reduce){
+.rd .apr-bar i{transition:none}
+}
+.rd .doc-mock{background:#fff;border:1px solid var(--line);border-radius:16px;padding:26px;font-size:.85rem;line-height:1.45;box-shadow:0 20px 40px -24px rgba(42,15,49,.3)}
+.rd .doc-mock .dh{display:flex;justify-content:space-between;align-items:center;padding-bottom:14px;border-bottom:2px solid var(--ink);margin-bottom:16px;font-weight:800;font-size:1rem}
+.rd .doc-block{position:relative;border:1px solid var(--line);border-radius:10px;padding:14px 14px 14px 52px;margin-bottom:10px;min-height:56px}
+.rd .doc-block .pin{position:absolute;left:10px;top:12px;transform:none;width:30px;height:30px;font-size:.85rem;border-width:2px}
+.rd .doc-block .pin[aria-pressed="true"]{transform:scale(1.1)}
+.rd .doc-block b{display:block;margin-bottom:4px}
+.rd .bg-form{background:#fff;border:2px solid var(--ink);border-radius:6px;padding:24px;font-size:.85rem;line-height:1.45}
+.rd .bg-form .t{text-align:center;font-weight:800;font-size:1.4rem;letter-spacing:.04em;border-bottom:2px solid var(--ink);padding-bottom:10px;margin-bottom:14px}
+.rd .box{display:flex;gap:10px;align-items:flex-start;border:1px solid var(--ink);padding:10px;margin-bottom:8px}
+.rd .box i{flex:0 0 16px;height:16px;border:2px solid var(--ink);margin-top:2px}
+.rd .key3 .card h4{font-size:1rem;letter-spacing:0;color:var(--purple);margin-bottom:8px}
+.rd .key3 .card h3{font-size:1.3rem;margin-bottom:10px}
+.rd .key3 .card p{line-height:1.7}
+.rd .chapters{display:grid;grid-template-columns:repeat(3,1fr);gap:24px;margin-top:48px}
+@media (max-width:960px){
+.rd .chapters{grid-template-columns:1fr}
+}
+.rd .chapter h3{font-size:1.5rem;margin:14px 0 4px}
+.rd .chapter .u{font-weight:600}
+.rd .chapter p.d{margin:16px 0;line-height:1.7}
+.rd .chapter .leads{font-size:.98rem;line-height:1.6;padding-top:16px;border-top:1px solid var(--line)}
+.rd .roles{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:40px}
+@media (max-width:860px){
+.rd .roles{grid-template-columns:1fr 1fr}
+}
+@media (max-width:520px){
+.rd .roles{grid-template-columns:1fr}
+}
+.rd .roles div{background:var(--bg);border-radius:18px;padding:22px}
+.rd .roles b{display:block;font-size:1.1rem;margin-bottom:4px}
+.rd form.apply{display:grid;grid-template-columns:1fr 1fr;gap:20px;margin-top:40px}
+@media (max-width:760px){
+.rd form.apply{grid-template-columns:1fr}
+}
+.rd .fld{display:flex;flex-direction:column;gap:8px}
+.rd .fld.full{grid-column:1/-1}
+.rd .fld label,.rd .fld legend{font-weight:700}
+.rd .fld input,.rd .fld select,.rd .fld textarea{font:inherit;color:var(--ink);background:#fff;border:1.5px solid var(--line);border-radius:14px;padding:13px 16px}
+.rd .fld input:focus,.rd .fld select:focus,.rd .fld textarea:focus{border-color:var(--purple);outline:none}
+.rd .fld textarea{min-height:130px;resize:vertical}
+.rd fieldset.fld{border:0;padding:0;margin:0}
+.rd .radios{display:flex;gap:18px}
+.rd .radios label{font-weight:600;display:flex;gap:8px;align-items:center}
+.rd .form-note{grid-column:1/-1;font-weight:600;line-height:1.6}
+.rd .form-ok{grid-column:1/-1;background:#e3f3e8;color:var(--green);border-radius:14px;padding:16px 18px;font-weight:700}
+.rd .campus-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:28px;margin-top:56px}
+@media (max-width:720px){
+.rd .campus-grid{grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:78%;overflow-x:auto;scroll-snap-type:x mandatory;gap:16px;padding-bottom:12px;margin-left:-20px;margin-right:-20px;padding-left:20px;padding-right:20px}
+.rd .campus{scroll-snap-align:start}
+}
+.rd .campus{display:flex;flex-direction:column;gap:22px;border-radius:24px;padding:14px 14px 26px;background:var(--bg);border:1px solid var(--line);transition:border-color .2s,box-shadow .2s}
+.rd .campus:hover{border-color:var(--purple);box-shadow:0 24px 48px -28px rgba(94,26,107,.45)}
+.rd .campus-img{position:relative;aspect-ratio:4/5;overflow:hidden;border-radius:999px 999px 16px 16px;background:linear-gradient(180deg,#e9d3ee 0%,#f6ecf8 62%,#fbf6fc 100%)}
+.rd .campus-img img{position:absolute;display:block}
+.rd .campus-img.royce img{left:50%;bottom:0;height:60%;width:auto;max-width:none;transform:translateX(-43%)}
+.rd .campus-img.tower img{left:50%;bottom:0;height:96%;width:auto;max-width:none;transform:translateX(-50%)}
+.rd .campus-img.photo img{inset:0;width:100%;height:100%;object-fit:cover;object-position:62% 60%}
+.rd .campus-body{padding:0 12px;display:flex;flex-direction:column;gap:10px;flex:1}
+.rd .campus-body .tag{align-self:flex-start}
+.rd .campus-body h3{font-size:clamp(1.2rem,1.9vw,1.45rem)}
+.rd .campus-body p{line-height:1.6;flex:1;font-size:.98rem}
+.rd .campus-go{display:inline-flex;align-items:center;gap:8px;font-weight:700;color:var(--purple);margin-top:4px}
+.rd .campus-go svg{transition:transform .2s}
+.rd .campus:hover .campus-go svg{transform:translateX(4px)}
+@media (prefers-reduced-motion:reduce){
+.rd .campus-go svg{transition:none}
+}
+.rd .avatar-img{width:96px;height:96px;border-radius:24px;object-fit:cover;display:block}
+.rd .socials{display:flex;gap:14px;flex-wrap:wrap}
+.rd .team{margin-top:40px}
+.rd .panel .sub{font-weight:700;margin-bottom:10px;color:var(--purple-deep)}
+.rd .panel .steps{margin:14px 0 0;padding-left:22px;display:flex;flex-direction:column;gap:8px;line-height:1.65}
+.rd .flagbox{margin-top:16px;border-radius:14px;padding:14px 16px;font-weight:600;line-height:1.6}
+.rd .stage .pin{width:32px;height:32px;font-size:.9rem}
+.rd .pin.sevpin-easy{background:#1d6b3a}
+.rd .pin.sevpin-watch{background:#a36a00}
+.rd .pin.sevpin-red{background:#b3261e}
+.rd .pin.sevpin-know{background:#9533A5}
+.rd .stage .pin[aria-pressed="true"]{outline:3px solid #fff;outline-offset:2px}
+.rd .title-real{position:relative;border-radius:16px;overflow:hidden;box-shadow:0 24px 48px -28px rgba(42,15,49,.45)}
+.rd .title-real img{display:block;width:100%;height:auto}
+.rd .title-real .zone{position:absolute;border:2px dashed rgba(149,51,165,.85);background:rgba(149,51,165,.10);border-radius:6px;cursor:pointer;padding:0;transition:background .2s}
+.rd .title-real .zone.danger{border-color:rgba(179,38,30,.85);background:rgba(179,38,30,.08)}
+.rd .title-real .zone:hover,.rd .title-real .zone[aria-pressed="true"]{background:rgba(149,51,165,.28)}
+.rd .title-real .zone.danger:hover,.rd .title-real .zone.danger[aria-pressed="true"]{background:rgba(179,38,30,.25)}
+.rd .bg-img{width:100%;height:auto;border-radius:12px;border:1px solid var(--line);box-shadow:0 20px 40px -24px rgba(42,15,49,.3);display:block}
+.rd details .say{margin-top:14px}
+.rd .team .card.member{border:3px solid #a53ab8;box-shadow:6px 6px 0 #7d2a8b}
+.rd .team .avatar-img,.rd .team .avatar{border:3px solid #a53ab8}
+@media (prefers-reduced-motion:reduce){
+.rd .team .card.member{transition:none}
+.rd .team .card.member:hover{transform:none}
+}
+.rd .tour{display:grid;grid-template-columns:1.1fr .9fr;gap:56px;margin-top:48px;align-items:start}
+.rd .tour-visual{position:sticky;top:calc(env(safe-area-inset-top,0px) + 100px);z-index:2}
+.rd .tour-frame{position:relative;overflow:hidden;border-radius:24px;background:var(--tint);box-shadow:0 30px 60px -30px rgba(42,15,49,.45)}
+.rd .tour-zoom{position:relative;transform-origin:0 0;transition:transform .9s cubic-bezier(.65,0,.25,1);will-change:transform}
+.rd .tour-zoom>img{display:block;width:100%;height:auto;user-select:none}
+.rd .spot{position:absolute;opacity:0;pointer-events:none;box-shadow:0 0 0 3px #fff,0 0 0 6px var(--purple),0 0 0 200vmax rgba(42,15,49,.55);transition:left .9s cubic-bezier(.65,0,.25,1),top .9s cubic-bezier(.65,0,.25,1),width .9s cubic-bezier(.65,0,.25,1),height .9s cubic-bezier(.65,0,.25,1),opacity .5s,border-radius .5s}
+.rd .spot.show{opacity:1}
+.rd .tour-hud{position:absolute;left:14px;right:14px;bottom:14px;display:flex;justify-content:space-between;align-items:center;gap:12px;pointer-events:none}
+.rd .tour-count{background:#fff;color:var(--ink);font-weight:800;border-radius:999px;padding:6px 14px;font-size:.92rem;font-variant-numeric:tabular-nums;box-shadow:0 6px 16px -8px rgba(42,15,49,.5)}
+.rd .tour-dots{display:flex;gap:6px;background:rgba(255,255,255,.9);border-radius:999px;padding:8px 10px}
+.rd .tour-dots i{width:8px;height:8px;border-radius:50%;background:var(--tint-2);transition:background .3s,transform .3s}
+.rd .tour-dots i.on{background:var(--purple);transform:scale(1.35)}
+.rd .tour-steps{display:flex;flex-direction:column}
+.rd .tour-step{min-height:78vh;display:flex;align-items:center;padding:6vh 0}
+.rd .tour-step:last-child{min-height:88vh}
+.rd .tour-intro{min-height:52vh;flex-direction:column;align-items:flex-start;justify-content:center;gap:12px}
+.rd .tour-intro p{font-size:1.35rem;font-weight:700;line-height:1.5;max-width:420px}
+.rd .tour-arrow{font-size:2rem;color:var(--purple);animation:rd-bob 1.6s ease-in-out infinite}
+@keyframes rd-bob{50%{transform:translateY(8px)}}
+.rd .tour-card{background:var(--bg);border:1px solid var(--line);border-radius:24px;padding:32px;opacity:.25;transform:translateX(24px) scale(.97);transition:opacity .5s,transform .5s,box-shadow .5s}
+.rd .band .tour-card{border-color:transparent}
+.rd .tour-step.on .tour-card{opacity:1;transform:none;box-shadow:0 24px 48px -30px rgba(94,26,107,.45)}
+.rd .tour-card h3{font-size:1.6rem;margin:12px 0}
+.rd .tour-card p{line-height:1.75}
+.rd .tour-card .sub{font-weight:700;margin-bottom:10px;color:var(--purple-deep)}
+.rd .tour-card .steps{margin:14px 0 0;padding-left:22px;display:flex;flex-direction:column;gap:8px;line-height:1.65}
+.rd .tour-doc .tour-frame{max-width:560px;margin:0 auto}
+.rd .doc-mock.tour-zoom{border:0;box-shadow:none;border-radius:0;transition:transform .9s cubic-bezier(.65,0,.25,1)}
+.rd .doc-block .pin-n{position:absolute;left:10px;top:12px;width:30px;height:30px;border-radius:50%;background:var(--purple);color:#fff;font-weight:800;font-size:.85rem;display:grid;place-items:center}
+@media (max-width:900px){
+.rd .tour{grid-template-columns:1fr;gap:0}
+.rd .tour-visual{top:calc(env(safe-area-inset-top,0px) + 76px);background:var(--bg);padding:10px 0 14px;box-shadow:0 14px 16px -12px rgba(42,15,49,.18)}
+.rd .band .tour-visual{background:var(--tint)}
+.rd .tour-frame{max-height:42vh;width:auto;margin:0 auto}
+.rd .tour-doc .tour-frame,.rd .tour-frame[style*="1040/1212"]{width:calc(42vh * 1040 / 1212);max-width:100%}
+.rd .tour-step{min-height:70vh}
+.rd .tour-card{padding:24px;transform:translateY(20px)}
+}
+@media (prefers-reduced-motion:reduce){
+.rd .tour-zoom,.rd .spot,.rd .tour-card{transition:none}
+.rd .tour-arrow{animation:none}
+}
+.rd .chat-phone{width:min(360px,100%);margin:0 auto;border-radius:40px;background:var(--ink);padding:12px;box-shadow:0 30px 60px -24px rgba(94,26,107,.5)}
+.rd .chat-top{display:flex;align-items:center;gap:12px;background:#fff;border-radius:28px 28px 0 0;padding:18px 18px 14px;border-bottom:1px solid var(--line)}
+.rd .chat-top b{display:block;line-height:1.2}
+.rd .chat-top span:not(.chat-av){font-size:.88rem;font-weight:600;color:var(--purple-deep)}
+.rd .chat-av{width:38px;height:38px;border-radius:50%;background:var(--tint-2);color:var(--purple-deep);display:grid;place-items:center;font-weight:800}
+.rd .chat-body{background:#fbf6fc;border-radius:0 0 28px 28px;min-height:420px;padding:18px 14px;display:flex;flex-direction:column;gap:10px}
+.rd .chat-note{align-self:center;font-size:.85rem;font-weight:700;color:var(--purple-deep);background:var(--tint-2);border-radius:999px;padding:4px 12px}
+.rd .bub{max-width:84%;padding:12px 15px;border-radius:20px;line-height:1.5;font-size:.98rem;animation:rd-pop .35s cubic-bezier(.2,.9,.3,1.3) both}
+.rd .bub.them{align-self:flex-start;background:#fff;border:1px solid var(--line);border-bottom-left-radius:6px}
+.rd .bub.me{align-self:flex-end;background:var(--purple);color:#fff;border-bottom-right-radius:6px;font-weight:600}
+.rd .bub.flagchip{align-self:center;background:#fbe1df;color:#7a1a14;font-weight:700;font-size:.9rem;border-radius:12px;max-width:100%}
+.rd .bub.flagchip b{margin-right:6px}
+@keyframes rd-pop{from{opacity:0;transform:translateY(12px) scale(.9)}to{opacity:1;transform:none}}
+.rd .typing{display:inline-flex;gap:4px;padding:4px 2px}
+.rd .typing i{width:7px;height:7px;border-radius:50%;background:currentColor;opacity:.4;animation:rd-blink 1s infinite}
+.rd .typing i:nth-child(2){animation-delay:.15s}
+.rd .typing i:nth-child(3){animation-delay:.3s}
+@keyframes rd-blink{50%{opacity:1;transform:translateY(-3px)}}
+@media (max-width:900px){
+.rd .chat-body{min-height:210px;max-height:240px;overflow:hidden;justify-content:flex-end;padding:12px}
+.rd .chat-top{padding:12px 14px 10px}
+.rd .chat-phone{border-radius:30px;padding:8px}
+.rd .bub{font-size:.9rem;padding:9px 12px}
+.rd .tour-chat .tour-visual{padding-bottom:10px}
+.rd .chat-phone{width:min(340px,100%)}
+}
+@media (prefers-reduced-motion:reduce){
+.rd .bub{animation:none}
+.rd .typing i{animation:none}
+}
+.rd .drive{height:420vh;padding:0}
+.rd .drive-sticky{position:sticky;top:calc(env(safe-area-inset-top,0px) + 76px);height:calc(100vh - 76px);height:calc(100svh - 76px);display:flex;align-items:center}
+.rd .drive-sticky .wrap{width:100%}
+.rd .drive-stage{position:relative;margin-top:28px}
+.rd .drive-road{width:100%;height:auto;aspect-ratio:1200/260;display:block;overflow:visible}
+.rd .dstop circle{transition:fill .3s}
+.rd .dstop.on circle{fill:#9533A5}
+.rd .dstop.on text{fill:#fff}
+.rd .drive-card{max-width:640px;margin:22px auto 0;background:var(--bg);border:1px solid var(--line);border-radius:24px;padding:26px 28px;text-align:left;box-shadow:0 24px 48px -30px rgba(94,26,107,.45)}
+.rd .drive-card h3{font-size:1.45rem;margin:10px 0 8px}
+.rd .drive-card p{line-height:1.7}
+.rd .drive-card.pop{opacity:0;transform:translateY(16px) scale(.97)}
+.rd .drive-card.pop.in{opacity:1;transform:none;transition:opacity .45s,transform .45s cubic-bezier(.2,.9,.3,1.2)}
+.rd .drive-alert{max-width:640px;margin:18px auto 0}
+@media (max-width:760px){
+.rd .drive-road{aspect-ratio:1200/360}
+.rd .drive-card{padding:20px}
+.rd .drive-alert{display:none}
+}
+@media (prefers-reduced-motion:reduce){
+.rd .drive{height:auto}
+.rd .drive-sticky{position:static;height:auto;padding:72px 0}
+.rd .drive-card.pop{opacity:1;transform:none}
+}
+.rd .rc-wrap{max-width:640px;margin:40px auto 0}
+.rd .rc-lines li{border-radius:10px}
+.rd .rc-lines .rc-note{display:grid;grid-template-rows:0fr;transition:grid-template-rows .35s ease}
+.rd .rc-lines .rc-note>div{overflow:hidden;padding:0 10px}
+.rd .rc-lines li.open .rc-note{grid-template-rows:1fr}
+.rd .rc-lines li.open .rc-note>div{padding:6px 10px 16px}
+.rd .rc-lines li.open{background:var(--tint)}
+.rd .rc-lines li.open button{background:transparent}
+.rd .rc-lines .rc-note p{margin-top:10px;line-height:1.65}
+.rd .rc-lines li.rc-red.open{background:#fdf0ef}
+@media (prefers-reduced-motion:reduce){
+.rd .rc-lines .rc-note{transition:none}
+}
+.rd .insp-bar{display:flex;justify-content:space-between;align-items:center;gap:20px;flex-wrap:wrap;margin-top:44px}
+.rd .insp-progress{display:flex;align-items:center;gap:14px;font-weight:700;flex:1;min-width:240px}
+.rd .insp-meter{flex:1;max-width:320px;height:12px;border-radius:6px;background:var(--bg);overflow:hidden}
+.rd .insp-meter i{display:block;height:100%;width:0;background:var(--purple);border-radius:6px;transition:width .5s cubic-bezier(.2,.9,.3,1)}
+.rd .insp-chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:18px}
+.rd .insp-chips button{display:inline-flex;align-items:center;gap:8px;border:1.5px solid var(--line);background:var(--bg);border-radius:999px;padding:8px 14px 8px 10px;font:inherit;font-weight:700;font-size:.92rem;color:var(--ink);cursor:pointer;transition:border-color .2s,background .2s}
+.rd .insp-chips button:hover{border-color:var(--purple)}
+.rd .insp-chips .ck{width:18px;height:18px;border-radius:50%;border:2px solid var(--line);display:grid;place-items:center;transition:background .2s,border-color .2s}
+.rd .insp-chips button.done .ck{background:var(--green);border-color:var(--green)}
+.rd .insp-chips button.done .ck::after{content:"";width:8px;height:4px;border:2.5px solid #fff;border-top:0;border-right:0;transform:rotate(-45deg) translate(1px,-1px)}
+.rd .insp-chips button.cur{border-color:var(--purple);background:var(--tint-2)}
+.rd .insp{margin-top:22px}
+.rd .insp-frame{position:relative;overflow:hidden;border-radius:24px;aspect-ratio:3/2;background:#e9e9ee;box-shadow:0 30px 60px -30px rgba(42,15,49,.45)}
+.rd .insp-zoom{position:absolute;inset:0;transform-origin:0 0;transition:transform .8s cubic-bezier(.65,0,.25,1);will-change:transform}
+.rd .insp-zoom img{display:block;width:100%;height:100%;object-fit:cover;user-select:none}
+.rd .insp-hots{position:absolute;inset:0;transition:opacity .3s}
+.rd .insp-frame.zoomed .insp-hots{opacity:0;pointer-events:none}
+.rd .hot{position:absolute;width:44px;height:44px;transform:translate(-50%,-50%);border:0;background:none;padding:0;cursor:pointer;--c:var(--purple)}
+.rd .hot.sevpin-easy{--c:#1d6b3a}
+.rd .hot.sevpin-watch{--c:#a36a00}
+.rd .hot.sevpin-red{--c:#b3261e}
+.rd .hot.sevpin-know{--c:#9533A5}
+.rd .hot-dot{position:absolute;inset:12px;border-radius:50%;background:var(--c);border:3px solid #fff;box-shadow:0 4px 10px rgba(0,0,0,.35)}
+.rd .hot-ring{position:absolute;inset:0;border-radius:50%;border:3px solid var(--c);animation:rd-ring 2s ease-out infinite}
+.rd .hot.done .hot-dot{background:var(--green)}
+.rd .hot.done .hot-dot::after{content:"";position:absolute;left:5px;top:5px;width:8px;height:4px;border:2.5px solid #fff;border-top:0;border-right:0;transform:rotate(-45deg)}
+.rd .hot.done .hot-ring{animation:none;opacity:0}
+@keyframes rd-ring{0%{transform:scale(.6);opacity:1}100%{transform:scale(1.5);opacity:0}}
+.rd .hot-tip{position:absolute;left:50%;bottom:calc(100% + 4px);transform:translate(-50%,6px);white-space:nowrap;background:var(--ink);color:#fff;font-weight:700;font-size:.85rem;padding:6px 10px;border-radius:8px;opacity:0;transition:opacity .2s,transform .2s;pointer-events:none}
+.rd .hot:hover .hot-tip,.rd .hot:focus-visible .hot-tip{opacity:1;transform:translate(-50%,0)}
+.rd .insp-card{position:absolute;top:16px;bottom:16px;width:min(44%,440px);background:rgba(255,255,255,.97);backdrop-filter:blur(8px);border-radius:20px;padding:26px 26px 20px;overflow:auto;box-shadow:0 30px 60px -20px rgba(42,15,49,.55);opacity:0;transition:opacity .45s .25s,transform .45s .25s cubic-bezier(.2,.9,.3,1.1)}
+.rd .insp-card[data-side="right"]{right:16px;transform:translateX(30px)}
+.rd .insp-card[data-side="left"]{left:16px;transform:translateX(-30px)}
+.rd .insp-card.in{opacity:1;transform:none}
+.rd .insp-card h3{font-size:1.55rem;margin:10px 0 6px}
+.rd .insp-card .sub{font-weight:700;color:var(--purple-deep);margin-bottom:8px}
+.rd .insp-card p{line-height:1.65}
+.rd .insp-x{position:absolute;top:12px;right:12px;width:36px;height:36px;border-radius:50%;border:0;background:var(--tint);font-size:1.4rem;line-height:1;cursor:pointer;color:var(--ink)}
+.rd .how{font-weight:800;margin-top:16px}
+.rd .todo{list-style:none;margin:8px 0 0;padding:0;display:flex;flex-direction:column;gap:8px}
+.rd .todo label{display:grid;grid-template-columns:22px 1fr;gap:10px;align-items:start;cursor:pointer;line-height:1.55}
+.rd .todo input{width:20px;height:20px;margin-top:2px;accent-color:var(--green)}
+.rd .todo input:checked+span{text-decoration:line-through;text-decoration-color:rgba(42,15,49,.4)}
+.rd .insp-nav{display:flex;justify-content:space-between;gap:10px;margin-top:18px;position:sticky;bottom:-20px;background:linear-gradient(transparent,#fff 30%);padding:14px 0 4px}
+.rd .insp-nav .btn{padding:12px 20px}
+.rd .insp-nav .btn[disabled]{opacity:.35;cursor:default}
+.rd .insp-done{margin-top:22px;background:#e3f3e8;color:#14512b;border-radius:18px;padding:18px 22px;display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;font-weight:600;line-height:1.55}
+@media (max-width:900px){
+.rd .insp-frame{overflow:visible;aspect-ratio:auto}
+.rd .insp-frame::before{content:"";display:block;aspect-ratio:3/2}
+.rd .insp-zoom,.rd .insp-hots{bottom:auto;height:0;padding-bottom:66.67%}
+.rd .insp-frame{border-radius:18px}
+.rd .insp-zoomwrap{}
+.rd .insp-card{position:relative;top:auto;bottom:auto;left:auto!important;right:auto!important;width:auto;margin-top:14px;transform:translateY(20px)!important;max-height:none}
+.rd .insp-card.in{transform:none!important}
+.rd .hot{width:36px;height:36px}
+.rd .hot-dot{inset:9px}
+}
+@media (prefers-reduced-motion:reduce){
+.rd .insp-zoom,.rd .insp-card,.rd .insp-meter i{transition:none}
+.rd .hot-ring{animation:none}
+}
+.rd .tour-card{opacity:.4}
+.rd .fv{display:grid;grid-template-columns:1.35fr .65fr;gap:48px;align-items:center}
+@media (max-width:900px){
+.rd .fv{grid-template-columns:1fr;gap:24px}
+}
+.rd .fv-player{position:relative;border-radius:28px;overflow:hidden;background:var(--ink);box-shadow:0 30px 60px -28px rgba(42,15,49,.5);aspect-ratio:16/9}
+.rd .fv-player video{display:block;width:100%;height:100%;object-fit:cover}
+.rd .fv-play{position:absolute;inset:0;border:0;padding:0;cursor:pointer;background:linear-gradient(180deg,transparent 55%,rgba(42,15,49,.55));display:grid;place-items:center;color:#fff}
+.rd .fv-btn{width:88px;height:88px;border-radius:50%;background:var(--purple);display:grid;place-items:center;box-shadow:0 0 0 10px rgba(255,255,255,.28);transition:transform .2s,box-shadow .2s}
+.rd .fv-btn svg{margin-left:4px}
+.rd .fv-play:hover .fv-btn{transform:scale(1.07);box-shadow:0 0 0 14px rgba(255,255,255,.32)}
+.rd .fv-len{position:absolute;right:18px;bottom:16px;background:rgba(42,15,49,.7);border-radius:999px;padding:5px 12px;font-weight:700;font-size:.9rem}
+.rd .fv-player.playing .fv-play{display:none}
+.rd .fv-text .lede{margin-top:16px}
+.rd .fv-who{margin-top:24px;padding-left:16px;border-left:4px solid var(--purple);line-height:1.5}
+.rd .fv-who b{display:block;font-size:1.1rem}
+@media (prefers-reduced-motion:reduce){
+.rd .fv-btn{transition:none}
+}
+.rd .avatar-play{position:relative;border:0;padding:0;background:none;cursor:pointer;align-self:flex-start;border-radius:24px}
+.rd .avatar-play .avatar-img{transition:transform .2s}
+@keyframes rd-ring2{0%{transform:scale(.96);opacity:.9}100%{transform:scale(1.12);opacity:0}}
+.rd .ap-badge{position:absolute;right:-8px;bottom:-8px;width:34px;height:34px;border-radius:50%;background:var(--purple);color:#fff;display:grid;place-items:center;border:3px solid #fff;box-shadow:0 4px 10px rgba(42,15,49,.3)}
+.rd .ap-badge svg{margin-left:2px}
+.rd .member.has-video .bio{cursor:pointer}
+.rd .watch{align-self:flex-start;display:inline-flex;align-items:center;gap:10px;border:0;background:var(--purple);color:#fff;font:inherit;font-weight:700;border-radius:999px;padding:9px 16px 9px 9px;cursor:pointer;transition:background .2s}
+.rd .watch:hover{background:var(--purple-dark)}
+.rd .w-ico{width:26px;height:26px;border-radius:50%;background:#fff;color:var(--purple);display:grid;place-items:center}
+.rd .w-ico svg{margin-left:2px}
+.rd .w-len{font-weight:600;opacity:.9;font-variant-numeric:tabular-nums}
+.rd .vbox{border:0;padding:0;background:transparent;max-width:min(960px,92vw);width:100%;overflow:visible}
+.rd .vbox::backdrop{background:rgba(42,15,49,.72);backdrop-filter:blur(4px)}
+.rd .vbox-in{position:relative;background:var(--ink);border-radius:24px;overflow:hidden;transform:scale(.92) translateY(20px);opacity:0;transition:transform .3s cubic-bezier(.2,.9,.3,1.15),opacity .25s}
+.rd .vbox.in .vbox-in{transform:none;opacity:1}
+.rd .vbox video{display:block;width:100%;aspect-ratio:16/9;background:#000}
+.rd .vbox-cap{color:#fff;padding:16px 20px;line-height:1.5}
+.rd .vbox-cap b{display:block;font-size:1.1rem}
+.rd .vbox-x{position:absolute;top:12px;right:12px;z-index:2;width:40px;height:40px;border-radius:50%;border:0;background:rgba(255,255,255,.92);color:var(--ink);font-size:1.5rem;line-height:1;cursor:pointer}
+@media (prefers-reduced-motion:reduce){
+.rd .avatar-play::before{animation:none}
+.rd .vbox-in{transition:none}
+}
+.rd .ig{display:grid;grid-template-columns:1fr minmax(300px,440px);gap:56px;align-items:center}
+@media (max-width:900px){
+.rd .ig{grid-template-columns:1fr;gap:28px}
+}
+.rd .ig-card{display:block;background:#fff;border:3px solid #a53ab8;box-shadow:6px 6px 0 #7d2a8b;border-radius:24px;overflow:hidden;transition:transform .15s,box-shadow .15s}
+.rd .ig-card:hover{transform:translate(-2px,-2px);box-shadow:8px 8px 0 #7d2a8b}
+.rd .ig-top{display:flex;align-items:center;gap:12px;padding:14px 16px;border-bottom:1px solid var(--line)}
+.rd .ig-top b{display:block;line-height:1.2}
+.rd .ig-top span{font-size:.9rem;font-weight:600;color:var(--purple-deep)}
+.rd .ig-av{width:40px;height:40px;object-fit:contain;border-radius:50%;background:var(--tint);padding:4px}
+.rd .ig-mark{margin-left:auto;color:var(--purple)}
+.rd .ig-media{aspect-ratio:1/1;background:radial-gradient(circle at 30% 25%,rgba(255,255,255,.35),transparent 55%),linear-gradient(140deg,#b75cc6,#5e1a6b);display:grid;place-items:center}
+.rd .ig-open{display:inline-flex;align-items:center;gap:10px;background:#fff;color:var(--purple-deep);font-weight:800;border-radius:999px;padding:12px 20px}
+.rd .ig-foot{padding:14px 16px;font-weight:600;font-size:.95rem}
+@media (prefers-reduced-motion:reduce){
+.rd .ig-card{transition:none}
+.rd .ig-card:hover{transform:none}
+}
+.rd .track-nav{position:sticky;top:calc(env(safe-area-inset-top,0px) + 76px);z-index:20;background:rgba(255,255,255,.95);backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
+.rd .track-nav .wrap{display:flex;gap:6px;overflow-x:auto;padding-top:10px;padding-bottom:10px;scrollbar-width:none}
+.rd .track-nav a{white-space:nowrap;font-weight:700;padding:9px 16px;border-radius:999px;display:inline-flex;gap:8px;align-items:center;transition:background .2s,color .2s}
+.rd .track-nav a b{font-size:.8rem;background:var(--tint-2);color:var(--purple-deep);border-radius:999px;padding:2px 8px}
+.rd .track-nav a.on{background:var(--purple);color:#fff}
+.rd .track-nav a.on b{background:#fff}
+.rd .track-head{display:flex;gap:20px;align-items:flex-start;margin-bottom:40px}
+.rd .track-head .icon{margin:0;flex:0 0 60px}
+.rd .track-head .lede{margin-top:10px}
+.rd .projects-2{grid-template-columns:repeat(2,1fr)}
+@media (max-width:1000px){
+.rd .projects-2{grid-template-columns:1fr}
+}
+.rd .proj{border:3px solid #a53ab8;box-shadow:6px 6px 0 #7d2a8b}
+.rd .proj:hover{transform:translate(-2px,-2px);box-shadow:8px 8px 0 #7d2a8b}
+.rd .band .proj{background:#fff}
+.rd .pir{margin-top:56px;background:#fff;border-radius:28px;padding:36px;border:3px solid #a53ab8;box-shadow:6px 6px 0 #7d2a8b}
+@media (max-width:640px){
+.rd .pir{padding:22px}
+}
+.rd .pir-head{display:flex;justify-content:space-between;gap:20px;align-items:flex-start;flex-wrap:wrap}
+.rd .pir-head h3{font-size:1.9rem;margin:10px 0 6px}
+.rd .pir-score{background:var(--ink);color:#fff;border-radius:18px;padding:12px 20px;text-align:center;min-width:120px}
+.rd .pir-score span{display:block;font-weight:600;font-size:.85rem}
+.rd .pir-score b{font-size:1.8rem;font-variant-numeric:tabular-nums}
+.rd .pir-game{display:grid;grid-template-columns:1fr 1fr;gap:28px;margin-top:28px;align-items:start}
+@media (max-width:900px){
+.rd .pir-game{grid-template-columns:1fr}
+}
+.rd .pir-photo{background:linear-gradient(180deg,#f6ecf8,#fff);border-radius:20px;padding:24px 20px 10px}
+.rd .pir-photo svg{width:100%;height:auto;display:block}
+.rd .pir-round{font-weight:700;color:var(--purple-deep);font-size:.92rem;display:block;margin-top:16px}
+.rd .pir-info h4{font-size:1.5rem;letter-spacing:-.02em;margin:4px 0 12px}
+.rd .pir-tags{display:flex;flex-wrap:wrap;gap:8px}
+.rd .pir-tags span{background:var(--tint);border-radius:999px;padding:6px 12px;font-weight:700;font-size:.92rem}
+.rd .pir-tags span.bad{background:#fbe1df;color:#7a1a14}
+.rd .pir-label{font-weight:800;display:block}
+.rd .pir-val{font-size:clamp(2.6rem,5vw,3.4rem);font-weight:800;color:var(--purple);letter-spacing:-.03em;font-variant-numeric:tabular-nums;margin:6px 0 14px}
+.rd #pirSlider{-webkit-appearance:none;appearance:none;width:100%;height:12px;border-radius:6px;background:linear-gradient(90deg,var(--purple) var(--fill,32%),var(--tint-2) var(--fill,32%))}
+.rd #pirSlider::-webkit-slider-thumb{-webkit-appearance:none;width:30px;height:30px;border-radius:50%;background:#fff;border:4px solid var(--purple);cursor:grab}
+.rd #pirSlider::-moz-range-thumb{width:24px;height:24px;border-radius:50%;background:#fff;border:4px solid var(--purple)}
+.rd .pir-scale{display:flex;justify-content:space-between;font-weight:600;font-size:.88rem;margin:8px 0 22px}
+.rd .pir-cmp{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
+.rd .pir-cmp div{background:var(--tint);border-radius:14px;padding:12px}
+.rd .pir-cmp span{display:block;font-weight:600;font-size:.85rem}
+.rd .pir-cmp b{font-size:1.25rem;font-variant-numeric:tabular-nums}
+.rd .pir-cmp b.fair{color:var(--purple)}
+.rd .pir-verdict{font-weight:800;font-size:1.15rem;margin:16px 0 14px}
+.rd .pir-verdict.over{color:var(--red)}
+.rd .pir-break{list-style:none;margin:8px 0 16px;padding:0;display:flex;flex-direction:column;gap:10px}
+.rd .pir-break li{display:grid;grid-template-columns:1fr 90px 82px;gap:10px;align-items:center;font-size:.95rem;opacity:0;transform:translateY(8px);transition:opacity .4s var(--d),transform .4s var(--d)}
+.rd .pir-reveal.go .pir-break li{opacity:1;transform:none}
+.rd .pir-break i{height:12px;border-radius:6px;width:0;transition:width .7s calc(var(--d) + 150ms) cubic-bezier(.2,.9,.3,1)}
+.rd .pir-reveal.go .pir-break i{width:var(--w)}
+.rd .pir-break i.base{background:var(--ink)}
+.rd .pir-break i.pos{background:var(--green)}
+.rd .pir-break i.neg{background:var(--red)}
+.rd .pir-break b{text-align:right;font-variant-numeric:tabular-nums}
+.rd .pir-reveal .btn{margin-top:18px}
+.rd .pir-end h4{font-size:2.4rem;color:var(--purple);margin:10px 0}
+.rd .pir-end p{line-height:1.7;margin-bottom:6px}
+.rd .plan-tl{margin-top:48px}
+.rd .plan-tl h3{font-size:1.6rem}
+.rd .plan-tl>p{margin-top:6px}
+.rd .tl6{list-style:none;padding:0;margin:28px 0 0;display:grid;grid-template-columns:repeat(6,1fr);gap:12px;position:relative}
+.rd .tl6::before{content:"";position:absolute;left:0;right:0;top:15px;height:4px;background:var(--tint-2);border-radius:2px}
+.rd .tl6 li{position:relative;padding-top:40px}
+.rd .tl6 li::before{content:"";position:absolute;top:4px;left:0;width:26px;height:26px;border-radius:50%;background:#fff;border:4px solid var(--tint-2)}
+.rd .tl6 li.past::before{background:var(--purple);border-color:var(--purple)}
+.rd .tl6 li.now::before{border-color:var(--purple);background:#fff;box-shadow:0 0 0 6px rgba(149,51,165,.2)}
+.rd .tl-w{display:block;font-weight:800}
+.rd .tl-d{display:block;font-weight:600;font-size:.9rem;color:var(--purple-deep)}
+.rd .tl6 p{margin-top:8px;font-size:.95rem;line-height:1.55}
+.rd .tl-now{display:inline-block;margin-top:10px;background:var(--purple);color:#fff;font-weight:700;font-size:.8rem;border-radius:999px;padding:4px 10px}
+@media (max-width:900px){
+.rd .tl6{grid-template-columns:1fr;gap:18px}
+.rd .tl6::before{left:11px;right:auto;top:0;bottom:0;width:4px;height:auto}
+.rd .tl6 li{padding:0 0 0 44px}
+.rd .tl6 li::before{top:0}
+}
+@media (prefers-reduced-motion:reduce){
+.rd .pir-break li,.rd .pir-break i{transition:none}
+}
+.rd .pir-start{margin-top:28px;background:var(--tint);border-radius:20px;padding:28px}
+.rd .pir-start p{margin:8px 0 18px;line-height:1.6;max-width:560px}
+.rd .pir-start-row{display:flex;gap:12px;flex-wrap:wrap}
+.rd #pirState{font:inherit;font-weight:600;color:var(--ink);background:#fff;border:1.5px solid var(--line);border-radius:14px;padding:13px 16px;min-width:240px}
+.rd #pirState:focus{outline:3px solid var(--purple);outline-offset:2px}
+.rd .pir-go[disabled],.rd #pirGo[disabled]{opacity:.45;cursor:default}
+.rd .pir-photo{background:#fff!important;border:1px solid var(--line);display:grid;place-items:center;aspect-ratio:16/10;overflow:hidden}
+.rd .pir-photo img{max-width:92%;max-height:88%;object-fit:contain;opacity:0;transform:translateX(40px);transition:opacity .5s,transform .6s cubic-bezier(.2,.9,.3,1)}
+.rd .pir-photo img.in{opacity:1;transform:none}
+.rd .pir-tags span.loc{background:var(--purple);color:#fff}
+.rd .pir-change{margin-top:12px;border:0;background:none;padding:0;font:inherit;font-weight:700;color:var(--purple);cursor:pointer;text-decoration:underline;text-underline-offset:3px}
+.rd .pir-break li.state{padding-top:10px;border-top:1px dashed var(--line)}
+.rd .pir-break i.zero{background:var(--tint-2)}
+@media (prefers-reduced-motion:reduce){
+.rd .pir-photo img{transition:none;opacity:1;transform:none}
+}
+.rd .pv-tag{background:var(--ink);color:#fff}
+.rd .pv{display:grid;grid-template-columns:1fr minmax(320px,480px);gap:56px;align-items:center}
+@media (max-width:900px){
+.rd .pv{grid-template-columns:1fr;gap:28px}
+}
+.rd .pv-card{background:#fff;border:3px solid #a53ab8;box-shadow:6px 6px 0 #7d2a8b;border-radius:24px;padding:22px}
+.rd .pv-photo{border-radius:16px;border:1px solid var(--line);aspect-ratio:16/9;display:grid;place-items:center;overflow:hidden;background:#fff}
+.rd .pv-photo img{max-width:90%;max-height:88%;object-fit:contain}
+.rd .pv-card h3{font-size:1.35rem;margin:16px 0 10px}
+.rd .pv-q{font-weight:800;margin:18px 0 10px}
+.rd .pv-opts{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
+.rd .pv-opts button{font:inherit;font-weight:800;font-size:1.1rem;padding:14px 8px;border-radius:14px;border:2px solid var(--line);background:#fff;color:var(--ink);cursor:pointer;transition:border-color .2s,background .2s,transform .15s;font-variant-numeric:tabular-nums}
+.rd .pv-opts button:hover:not(:disabled){border-color:var(--purple);transform:translateY(-2px)}
+.rd .pv-opts button:disabled{cursor:default}
+.rd .pv-opts button.right{background:#e3f3e8;border-color:var(--green);color:#14512b}
+.rd .pv-opts button.wrong{background:#fbe1df;border-color:var(--red);color:#7a1a14}
+.rd .pv-out{margin-top:14px;line-height:1.6;opacity:0;transform:translateY(8px);transition:opacity .35s,transform .35s}
+.rd .pv-out.in{opacity:1;transform:none}
+.rd .pv-out a{color:var(--purple);font-weight:800}
+@media (prefers-reduced-motion:reduce){
+.rd .pv-out,.rd .pv-opts button{transition:none}
+}
+.rd .socials-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:20px;margin-top:48px}
+@media (max-width:1000px){
+.rd .socials-grid{grid-template-columns:1fr 1fr}
+}
+@media (max-width:560px){
+.rd .socials-grid{grid-template-columns:1fr}
+}
+.rd .soc{position:relative;display:flex;flex-direction:column;align-items:flex-start;gap:14px;background:#fff;border:3px solid #a53ab8;box-shadow:6px 6px 0 #7d2a8b;border-radius:22px;padding:20px;transition:transform .15s,box-shadow .15s}
+.rd .soc:hover{transform:translate(-2px,-2px);box-shadow:8px 8px 0 #7d2a8b}
+.rd .soc-ic{flex:none;width:52px;height:52px;border-radius:16px;background:var(--tint-2);color:var(--purple);display:grid;place-items:center}
+.rd .soc-txt{min-width:0}
+.rd .soc-pf{display:block;font-weight:700;font-size:.9rem;color:var(--purple-deep)}
+.rd .soc-txt b{display:block;font-size:1.12rem;white-space:nowrap}
+.rd .soc-go{position:absolute;top:22px;right:20px;color:var(--purple);transition:transform .2s}
+.rd .soc:hover .soc-go{transform:translate(2px,-2px)}
+@media (prefers-reduced-motion:reduce){
+.rd .soc,.rd .soc-go{transition:none}
+.rd .soc:hover{transform:none}
+}
+.rd .yoyo{height:380vh;padding:0}
+.rd .yoyo-sticky{position:sticky;top:calc(env(safe-area-inset-top,0px) + 76px);height:calc(100vh - 76px);height:calc(100svh - 76px);display:flex;align-items:center}
+.rd .yoyo-sticky .wrap{width:100%}
+.rd .yoyo-stage{position:relative;margin-top:24px}
+.rd .yoyo-svg{width:100%;height:auto;display:block;overflow:visible}
+.rd #yyPhone.ring{animation:rd-ring3 .35s ease-in-out infinite;transform-box:fill-box;transform-origin:center}
+@keyframes rd-ring3{0%,100%{transform:rotate(-6deg)}50%{transform:rotate(6deg)}}
+.rd .yy-day{position:absolute;top:4%;left:50%;transform:translateX(-50%);background:var(--ink);color:#fff;font-weight:800;border-radius:999px;padding:8px 18px;font-variant-numeric:tabular-nums}
+.rd .yy-contract{position:absolute;top:0;left:2%;border-radius:16px;padding:12px 16px;display:flex;flex-direction:column;gap:2px;border:3px solid;box-shadow:5px 5px 0 currentColor;background:#fff;transition:transform .35s;animation:rd-flip .5s ease}
+.rd .yy-contract.ok{color:#1d6b3a}
+.rd .yy-contract.bad{color:#b3261e}
+.rd .yy-contract span{font-weight:700;font-size:.85rem}
+.rd .yy-contract b{font-size:1.4rem;color:var(--ink)}
+.rd .yy-contract em{font-style:normal;font-weight:800}
+@keyframes rd-flip{from{transform:rotateY(90deg)}to{transform:none}}
+.rd .yy-caption{max-width:680px;margin:18px auto 0;text-align:center;min-height:96px}
+.rd .yy-caption p{margin-top:10px;font-size:1.2rem;font-weight:700;line-height:1.5}
+.rd .yy-caption.in{animation:rd-pop .4s cubic-bezier(.2,.9,.3,1.2)}
+@media (max-width:760px){
+.rd .yy-contract{position:static;margin:0 auto 10px;width:max-content}
+.rd .yy-day{top:auto;bottom:-6px}
+.rd .yy-caption p{font-size:1.05rem}
+}
+@media (prefers-reduced-motion:reduce){
+.rd .yoyo{height:auto}
+.rd .yoyo-sticky{position:static;height:auto;padding:72px 0}
+.rd #yyPhone.ring{animation:none}
+}
+.rd .fs{display:grid;grid-template-columns:1fr 1fr;gap:48px;align-items:start}
+@media (max-width:900px){
+.rd .fs{grid-template-columns:1fr;gap:28px}
+}
+.rd .fs-paper-wrap{position:relative;padding-bottom:70px}
+.rd .fs-paper{position:relative;z-index:2;display:grid;grid-template-columns:1fr 1fr;background:#fffdf7;border-radius:6px;box-shadow:0 24px 48px -26px rgba(42,15,49,.45);transform:rotate(-1.5deg);background-image:repeating-linear-gradient(transparent 0 31px,#e7dff0 31px 32px)}
+.rd .fs-cell{position:relative;padding:28px 22px 34px;min-height:150px;border:2px solid #2a0f31;margin:-1px}
+.rd .fs-cell span{display:block;font-weight:700;font-size:.95rem}
+.rd .fs-cell b{display:block;font-family:"Caveat","Segoe Print","Comic Sans MS",cursive;font-size:2.6rem;font-weight:700;color:#1b3a8a;margin-top:10px;line-height:1}
+.rd .fs-pay{background:rgba(149,51,165,.08)}
+.rd .fs-pay b.pop{animation:rd-pop .45s cubic-bezier(.2,.9,.3,1.3)}
+.rd .fs-pay s{position:absolute;right:18px;top:26px;font-family:"Caveat","Segoe Print",cursive;font-size:1.6rem;color:#b3261e;opacity:0}
+.rd .fs-pay s.go{animation:rd-strike .9s ease forwards}
+@keyframes rd-strike{0%{opacity:1;transform:none}100%{opacity:.55;transform:translateY(-4px) rotate(-6deg)}}
+.rd .fs-hidden{position:absolute;left:10%;right:10%;bottom:0;z-index:1;background:#b3261e;color:#fff;border-radius:0 0 16px 16px;padding:16px 20px 14px;display:flex;justify-content:space-between;align-items:baseline;gap:12px;transform:translateY(-70px);opacity:0;transition:transform .6s cubic-bezier(.2,.9,.3,1.1),opacity .4s}
+.rd .fs-hidden.out{transform:none;opacity:1}
+.rd .fs-hidden span{font-weight:700;font-size:.9rem}
+.rd .fs-hidden b{font-size:1.5rem;font-variant-numeric:tabular-nums}
+.rd .fs-hidden.bump b{animation:rd-pop .45s cubic-bezier(.2,.9,.3,1.3)}
+.rd .fs-chat{background:#fff;border-radius:20px;padding:16px;display:flex;flex-direction:column;gap:10px;min-height:250px;max-height:320px;overflow:auto;border:1px solid var(--line)}
+.rd .fs-total{margin-top:18px;background:#fff;border-radius:18px;padding:18px 20px}
+.rd .fs-total-row{display:flex;justify-content:space-between;align-items:baseline;font-weight:700}
+.rd .fs-total-row b{font-size:1.6rem;font-variant-numeric:tabular-nums}
+.rd .fs-bar{display:flex;height:16px;border-radius:8px;overflow:hidden;background:var(--tint);margin-top:12px}
+.rd .fs-bar i{display:block;height:100%;transition:width .6s cubic-bezier(.2,.9,.3,1)}
+.rd #fsBarP{background:var(--ink)}
+.rd #fsBarI{background:var(--red)}
+.rd #fsAsk[disabled]{opacity:.4;cursor:default}
+@media (prefers-reduced-motion:reduce){
+.rd .fs-hidden,.rd .fs-bar i{transition:none}
+}
+.rd .bro{display:grid;grid-template-columns:minmax(200px,300px) 1fr;gap:56px;align-items:center;background:var(--tint);border-radius:32px;padding:44px}
+@media (max-width:760px){
+.rd .bro{grid-template-columns:1fr;padding:28px;gap:28px}
+}
+.rd .bro-cover{perspective:900px}
+.rd .bro-cover img{width:100%;border-radius:10px;display:block;box-shadow:12px 18px 40px -12px rgba(42,15,49,.5);transform:rotateY(-14deg) rotateZ(-2deg);transition:transform .5s}
+.rd .bro-cover:hover img{transform:rotateY(0) rotateZ(0)}
+.rd .bro-soon{margin-top:22px;display:inline-flex;align-items:center;gap:10px;background:#fff;border-radius:999px;padding:10px 18px;font-weight:700}
+.rd .dot-live{width:10px;height:10px;border-radius:50%;background:var(--purple);box-shadow:0 0 0 0 rgba(149,51,165,.5);animation:rd-live 1.6s infinite}
+@keyframes rd-live{70%{box-shadow:0 0 0 10px rgba(149,51,165,0)}100%{box-shadow:0 0 0 0 rgba(149,51,165,0)}}
+@media (prefers-reduced-motion:reduce){
+.rd .dot-live{animation:none}
+.rd .bro-cover img{transition:none}
+}
+.rd .vbox.portrait{max-width:min(400px,92vw)}
+.rd .vbox.portrait video{aspect-ratio:9/16;max-height:78vh;object-fit:cover}
+.rd .t-flagged{--tc:#b3261e}
+.rd .t-caution{--tc:#b07a00}
+.rd .t-clear{--tc:#1d6b3a}
+.rd .t-all{--tc:var(--purple)}
+.rd .dm-bar{display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap}
+.rd .dm-chips{display:flex;gap:8px;flex-wrap:wrap}
+.rd .dm-chips button{display:inline-flex;align-items:center;gap:8px;font:inherit;font-weight:700;border:1.5px solid var(--line);background:#fff;border-radius:999px;padding:9px 16px;cursor:pointer;color:var(--ink)}
+.rd .dm-chips button i,.rd .dm-list i,.rd .dm-key i{width:12px;height:12px;border-radius:50%;background:var(--tc);display:inline-block;flex:none}
+.rd .dm-chips button b{font-size:.82rem;background:var(--tint);border-radius:999px;padding:1px 8px}
+.rd .dm-chips button[aria-pressed="true"]{border-color:var(--ink);background:var(--ink);color:#fff}
+.rd .dm-chips button[aria-pressed="true"] b{background:rgba(255,255,255,.2)}
+.rd .dm-search{display:flex;align-items:center;gap:8px;border:1.5px solid var(--line);border-radius:999px;padding:0 16px;background:#fff;min-width:260px}
+.rd .dm-search input{border:0;outline:0;font:inherit;padding:11px 0;width:100%;background:none;color:var(--ink)}
+.rd .dm-search:focus-within{border-color:var(--purple)}
+.rd .dm{display:grid;grid-template-columns:1fr 340px;gap:20px;margin-top:20px}
+@media (max-width:960px){
+.rd .dm{grid-template-columns:1fr}
+}
+.rd .dm-map{position:relative;border-radius:24px;overflow:hidden;border:3px solid #a53ab8;box-shadow:6px 6px 0 #7d2a8b;background:#faf6fb;touch-action:none;height:clamp(420px,62vh,640px)}
+.rd .dm-map svg{display:block;width:100%;height:100%;cursor:grab}
+.rd .dm-map.grab svg{cursor:grabbing}
+.rd .dm-city{font:800 17px "Plus Jakarta Sans",sans-serif;fill:#5e1a6b;opacity:.55;pointer-events:none;letter-spacing:.02em}
+.rd .dm-city.sea{fill:#5b7fa8;font-style:italic;font-weight:700}
+.rd .dm-pin{cursor:pointer;outline:none}
+.rd .dm-pin .dot{fill:var(--tc);stroke:#fff;stroke-width:2.5;transition:r .2s}
+.rd .dm-pin .ring{fill:none;stroke:var(--tc);stroke-width:2;opacity:0}
+.rd .dm-map.live .dm-pin .ring{animation:rd-dmring 2.2s ease-out infinite var(--d)}
+@keyframes rd-dmring{0%{r:7;opacity:.9}100%{r:22;opacity:0}}
+.rd .dm-pin{opacity:0;transition:opacity .4s}
+.rd .dm-map.live .dm-pin{opacity:1;animation:rd-dmdrop .6s cubic-bezier(.2,.9,.3,1.4) both var(--d)}
+@keyframes rd-dmdrop{from{opacity:0;translate:0 -30px}to{opacity:1;translate:0 0}}
+.rd .dm-pin:hover .dot,.rd .dm-pin:focus-visible .dot,.rd .dm-pin.sel .dot{r:10;stroke:var(--ink)}
+.rd .dm-pin.dim{opacity:.12!important;pointer-events:none}
+.rd .dm-tip{position:absolute;transform:translate(-50%,-100%);background:var(--ink);color:#fff;font-weight:700;font-size:.85rem;padding:6px 10px;border-radius:8px;pointer-events:none;white-space:nowrap}
+.rd .dm-pop{position:absolute;width:min(340px,calc(100% - 20px));max-height:calc(100% - 20px);overflow:auto;background:#fff;border-radius:18px;padding:20px;box-shadow:0 24px 48px -16px rgba(42,15,49,.5);border:1px solid var(--line);opacity:0;transform:scale(.94);transition:opacity .3s,transform .3s cubic-bezier(.2,.9,.3,1.2)}
+.rd .dm-pop.in{opacity:1;transform:none}
+.rd .dm-x{position:absolute;top:10px;right:10px;width:32px;height:32px;border-radius:50%;border:0;background:var(--tint);font-size:1.3rem;cursor:pointer;color:var(--ink)}
+.rd .dm-badge{display:inline-block;font-weight:800;font-size:.82rem;color:#fff;background:var(--tc);border-radius:999px;padding:4px 12px}
+.rd .dm-pop h3{font-size:1.25rem;margin:10px 30px 4px 0;letter-spacing:-.015em}
+.rd .dm-addr{font-size:.92rem;line-height:1.45}
+.rd .dm-rev{display:flex;align-items:center;gap:5px;margin-top:14px;flex-wrap:wrap}
+.rd .dm-rev i{width:16px;height:16px;border-radius:4px;background:#e3f3e8}
+.rd .dm-rev i.bad{background:#b3261e}
+.rd .dm-rev span{margin-left:6px;font-size:.92rem}
+.rd .dm-h{font-weight:800;margin-top:16px;font-size:.95rem}
+.rd .dm-cats{list-style:none;margin:8px 0 0;padding:0;display:flex;flex-direction:column;gap:6px}
+.rd .dm-cats li{background:var(--tint);border-radius:10px;padding:8px 12px;font-size:.92rem}
+.rd .dm-cat-top{display:flex;justify-content:space-between;gap:10px;font-weight:600}
+.rd .dm-cats q{display:block;margin-top:6px;padding-left:10px;border-left:3px solid var(--tc);font-style:italic;line-height:1.5;font-size:.9rem}
+.rd .dm-cats q::before{content:"“"}
+.rd .dm-cats q::after{content:"”"}
+.rd .dm-attr{margin-top:8px;font-size:.82rem;font-weight:600;color:var(--purple-deep)}
+.rd .dm-ok{margin-top:14px;font-weight:600;color:#14512b}
+.rd .dm-link{display:inline-block;margin-top:16px;font-weight:800;color:var(--purple)}
+.rd .dm-ctrl{position:absolute;right:14px;top:14px;display:flex;flex-direction:column;gap:6px}
+.rd .dm-ctrl button{width:40px;height:40px;border-radius:12px;border:1px solid var(--line);background:#fff;font:inherit;font-size:1.3rem;font-weight:700;cursor:pointer;color:var(--ink);box-shadow:0 4px 10px -4px rgba(42,15,49,.3)}
+.rd .dm-note{position:absolute;left:14px;bottom:12px;background:rgba(255,255,255,.9);border-radius:999px;padding:5px 12px;font-size:.82rem;font-weight:600}
+.rd .dm-side{display:flex;flex-direction:column;min-height:0;height:clamp(420px,62vh,640px);background:#fff;border:1px solid var(--line);border-radius:24px;overflow:hidden}
+@media (max-width:960px){
+.rd .dm-side{height:360px}
+}
+.rd .dm-count{padding:16px 18px;font-weight:800;border-bottom:1px solid var(--line)}
+.rd .dm-list{list-style:none;margin:0;padding:6px;overflow:auto;flex:1}
+.rd .dm-list button{width:100%;display:flex;gap:12px;align-items:flex-start;text-align:left;border:0;background:none;padding:10px 12px;border-radius:12px;font:inherit;color:var(--ink);cursor:pointer}
+.rd .dm-list i{margin-top:5px}
+.rd .dm-list b{display:block;font-size:.98rem}
+.rd .dm-list em{font-style:normal;font-size:.86rem;color:var(--purple-deep);font-weight:600}
+.rd .dm-list button:hover{background:var(--tint)}
+.rd .dm-list li.sel button{background:var(--tint-2)}
+.rd .dm-empty{padding:18px;font-weight:600}
+.rd .dm-key{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:24px}
+@media (max-width:760px){
+.rd .dm-key{grid-template-columns:1fr}
+}
+.rd .dm-key div{display:grid;grid-template-columns:14px 1fr;gap:4px 10px;align-items:center;background:var(--tint);border-radius:16px;padding:14px 16px}
+.rd .dm-key span{grid-column:2;font-size:.94rem;line-height:1.5}
+@media (prefers-reduced-motion:reduce){
+.rd .dm-map.live .dm-pin{animation:none;opacity:1}
+.rd .dm-pin{opacity:1}
+.rd .dm-map.live .dm-pin .ring{animation:none}
+.rd .dm-pop{transition:none}
+}
+.rd .dm-sat{display:flex;align-items:center;gap:16px;background:var(--ink);color:#fff;border-radius:20px;padding:16px 20px;margin-bottom:20px;transition:transform .15s}
+.rd .dm-sat:hover{transform:translateY(-2px)}
+.rd .dm-sat-ic{width:44px;height:44px;border-radius:14px;background:var(--purple);display:grid;place-items:center;flex:none}
+.rd .dm-sat b{display:block;font-size:1.05rem}
+.rd .dm-sat em{font-style:normal;font-size:.92rem;opacity:.9}
+.rd .dm-sat-go{margin-left:auto;font-size:1.4rem;font-weight:800}
+.rd .dm-cats-key{margin-top:28px;background:#fff;border:1px solid var(--line);border-radius:24px;padding:28px}
+.rd .dm-cats-key h3{font-size:1.4rem}
+.rd .dm-cats-key>p{margin-top:8px;line-height:1.6;max-width:760px}
+.rd .dm-cats-key ol{list-style:none;counter-reset:c;margin:20px 0 0;padding:0;display:grid;grid-template-columns:repeat(2,1fr);gap:14px 28px}
+@media (max-width:760px){
+.rd .dm-cats-key ol{grid-template-columns:1fr}
+}
+.rd .dm-cats-key li{display:grid;grid-template-columns:34px 1fr;gap:2px 12px;counter-increment:c}
+.rd .dm-cats-key li::before{content:counter(c);grid-row:span 2;width:34px;height:34px;border-radius:10px;background:var(--tint-2);color:var(--purple-deep);display:grid;place-items:center;font-weight:800}
+.rd .dm-cats-key li span{font-size:.94rem;line-height:1.5}
+.rd .vd{background:#fff;border:4px solid var(--ink);box-shadow:10px 10px 0 var(--purple);border-radius:28px;padding:clamp(24px,4vw,52px)}
+.rd .vd-head{border-bottom:3px solid var(--ink);padding-bottom:24px;margin-bottom:28px}
+.rd .vd-title{font-size:clamp(2.6rem,6vw,4.6rem);letter-spacing:-.04em;line-height:1}
+.rd .vd-lede{margin-top:14px;font-size:1.2rem;font-weight:600;line-height:1.6;max-width:720px}
+.rd .vd-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:18px}
+@media (max-width:820px){
+.rd .vd-grid{grid-template-columns:1fr}
+}
+.rd .vd-item{background:var(--tint);border-radius:18px;padding:22px 22px 20px;position:relative}
+.rd .vd-item:first-child{grid-column:1/-1;background:var(--ink);color:#fff}
+.rd .vd-item:first-child .vd-n{background:var(--purple);color:#fff}
+.rd .vd-n{display:inline-block;font-weight:800;font-size:.85rem;background:#fff;color:var(--purple-deep);border-radius:999px;padding:3px 10px;margin-bottom:10px;font-variant-numeric:tabular-nums}
+.rd .vd-item h3{font-size:1.2rem;margin-bottom:8px;letter-spacing:-.015em}
+.rd .vd-item:first-child h3{font-size:1.6rem}
+.rd .vd-item p{line-height:1.65}
+.rd .vd-sub{font-size:clamp(2rem,4vw,2.8rem);margin:44px 0 20px}
+.rd .vd-steps{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(4,1fr);gap:16px;position:relative}
+@media (max-width:980px){
+.rd .vd-steps{grid-template-columns:1fr 1fr}
+}
+@media (max-width:560px){
+.rd .vd-steps{grid-template-columns:1fr}
+}
+.rd .vd-steps li{border:3px solid #a53ab8;box-shadow:6px 6px 0 #7d2a8b;border-radius:20px;padding:22px;background:#fff}
+.rd .vd-sn{width:42px;height:42px;border-radius:12px;background:var(--purple);color:#fff;display:grid;place-items:center;font-weight:800;font-size:1.2rem;margin-bottom:14px}
+.rd .vd-steps h3{font-size:1.3rem;margin-bottom:8px}
+.rd .vd-steps p{line-height:1.6;font-size:.98rem}
+.rd .vd .dm-cats-key{margin-top:28px;border:0;background:var(--tint)}
+.rd .vd-fine{margin-top:18px;font-weight:600;font-size:.92rem;color:var(--purple-deep)}
+.rd .vd-accept{margin-top:32px;border-top:3px solid var(--ink);padding-top:26px;display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap}
+.rd .vd-check{display:flex;gap:14px;align-items:flex-start;max-width:720px;cursor:pointer;font-weight:700;line-height:1.55;font-size:1.05rem}
+.rd .vd-check input{width:26px;height:26px;margin-top:1px;accent-color:var(--purple);flex:none}
+.rd .vd-go{font:inherit;font-weight:800;font-size:1.1rem;border:0;border-radius:999px;padding:16px 30px;background:var(--purple);color:#fff;cursor:pointer;transition:background .2s,opacity .2s}
+.rd .vd-go:hover:not(:disabled){background:var(--purple-dark)}
+.rd .vd-go:disabled{opacity:.35;cursor:not-allowed}
+.rd .vd.done{opacity:.55}
+.rd .vd-launch{display:flex;align-items:center;gap:18px;background:var(--ink);color:#fff;border-radius:24px;padding:22px 26px;margin-top:28px;box-shadow:8px 8px 0 var(--purple)}
+.rd .vd-launch.in{animation:rd-pop .5s cubic-bezier(.2,.9,.3,1.3)}
+.rd .vd-launch-ic{width:56px;height:56px;border-radius:16px;background:var(--purple);display:grid;place-items:center;flex:none}
+.rd .vd-launch b{display:block;font-size:1.35rem}
+.rd .vd-launch em{font-style:normal;opacity:.9}
+.rd .vd-launch-go{margin-left:auto;font-size:1.8rem;font-weight:800}
+.rd .nw-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:24px;margin-top:48px}
+@media (max-width:640px){
+.rd .nw-grid{grid-template-columns:1fr}
+}
+.rd .nw{display:flex;flex-direction:column;background:#fff;border-radius:6px;overflow:hidden;box-shadow:0 1px 0 var(--line),0 18px 40px -26px rgba(42,15,49,.45);transition:transform .2s,box-shadow .2s}
+.rd .nw:hover{transform:translateY(-3px);box-shadow:0 1px 0 var(--line),0 26px 50px -24px rgba(42,15,49,.5)}
+.rd .nw:hover h3{text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:4px}
+.rd .nw-img{position:relative;aspect-ratio:16/9;overflow:hidden;background:#2a0f31}
+.rd .nw-img svg{display:block;width:100%;height:100%}
+.rd .nw-credit{position:absolute;left:0;bottom:0;background:#1b1b1b;color:#fff;font-size:.75rem;font-style:italic;padding:5px 10px}
+.rd .nw-body{padding:20px 22px 22px;display:flex;flex-direction:column;gap:8px;flex:1}
+.rd .nw-kicker{font-size:.78rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:#c2410c}
+.rd .nw h3{font-family:"Bitter",Georgia,serif;font-weight:700;font-size:1.45rem;line-height:1.2;letter-spacing:-.01em}
+.rd .nw-by{font-size:.74rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase}
+.rd .nw-dek{font-family:"Bitter",Georgia,serif;font-weight:400;font-size:1.02rem;line-height:1.6;flex:1}
+.rd .nw-take{margin-top:6px;background:var(--tint);border-radius:12px;padding:12px 14px;line-height:1.55;font-weight:600}
+.rd .nw-take b{display:block;font-size:.8rem;color:var(--purple);margin-bottom:2px;text-transform:uppercase;letter-spacing:.06em}
+.rd .nw-go{margin-top:6px;font-weight:800;color:var(--purple)}
+.rd .nw:first-child{grid-column:1/-1;flex-direction:row}
+.rd .nw:first-child .nw-img{flex:0 0 56%;aspect-ratio:auto;min-height:360px}
+.rd .nw:first-child h3{font-size:2.2rem}
+.rd .nw:first-child .nw-dek{font-size:1.15rem}
+@media (max-width:900px){
+.rd .nw:first-child{flex-direction:column}
+.rd .nw:first-child .nw-img{flex:none;aspect-ratio:16/9;min-height:0}
+.rd .nw:first-child h3{font-size:1.7rem}
+}
+@media (prefers-reduced-motion:reduce){
+.rd .nw{transition:none}
+.rd .nw:hover{transform:none}
+}
+.rd .hero-photo{position:relative;margin:0;justify-self:center;width:100%;max-width:600px;padding:28px 0 36px}
+.rd .hero-photo img{display:block;width:100%;aspect-ratio:6/5;object-fit:cover;object-position:40% 60%;border-radius:28px;border:3px solid #a53ab8;box-shadow:8px 8px 0 #7d2a8b}
+.rd .hp-card{position:absolute;display:flex;align-items:center;gap:12px;background:#fff;border-radius:16px;padding:11px 16px 11px 11px;box-shadow:0 16px 32px -14px rgba(42,15,49,.45);animation:rd-hb-float 6s ease-in-out infinite}
+.rd .hp-card b{display:block;font-size:.95rem;line-height:1.2}
+.rd .hp-card em{display:block;font-style:normal;font-size:.82rem;font-weight:600;color:var(--purple-deep)}
+.rd .hp-ic{width:34px;height:34px;border-radius:50%;display:grid;place-items:center;font-weight:800;flex:none}
+.rd .hp-ic.ok{background:#e3f3e8;color:#1d6b3a}
+.rd .hp-ic.bad{background:#fbe1df;color:#b3261e;font-size:1.1rem}
+.rd .hp-ic.pur{background:var(--purple);color:#fff}
+.rd .hp-c1{left:-28px;bottom:14%}
+.rd .hp-c2{right:-18px;top:0;animation-delay:-2s}
+.rd .hp-c3{right:-18px;bottom:6px;animation-delay:-4s}
+@media (max-width:960px){
+.rd .hp-c1{left:-6px}
+.rd .hp-c2{right:-6px}
+.rd .hp-c3{right:-6px}
+}
+@media (max-width:520px){
+.rd .hp-c1{display:none}
+}
+@media (prefers-reduced-motion:reduce){
+.rd .hp-card{animation:none}
+}
+.rd-ftr{background:var(--ink);color:#fff;padding:80px 0 40px}
+.rd .fgrid{display:grid;grid-template-columns:1.6fr 1fr 1fr 1fr;gap:48px}
+@media (max-width:900px){
+.rd .fgrid{grid-template-columns:1fr 1fr}
+}
+@media (max-width:520px){
+.rd .fgrid{grid-template-columns:1fr}
+}
+.rd .fgrid>div:first-child p{margin-top:18px;line-height:1.7;max-width:420px}
+.rd-ftr h4{font-size:1.05rem;margin-bottom:16px;letter-spacing:0}
+.rd-ftr ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:11px}
+.rd-ftr ul a:hover{color:#e0b3e8}
+.rd .fbot{margin-top:56px;padding-top:24px;border-top:1px solid rgba(255,255,255,.2);display:flex;justify-content:space-between;flex-wrap:wrap;gap:12px}
+@media (prefers-reduced-motion:reduce){
+.rd .notif{opacity:1;transform:none}
+}
diff --git a/app/sitemap.ts b/app/sitemap.ts
index dc6efb2..105c6d7 100644
--- a/app/sitemap.ts
+++ b/app/sitemap.ts
@@ -11,7 +11,9 @@ const routes = [
{ href: "/fraud", changeFrequency: "monthly", priority: 0.8 },
{ href: "/documents", changeFrequency: "monthly", priority: 0.8 },
{ href: "/rights", changeFrequency: "monthly", priority: 0.7 },
+ { href: "/research", changeFrequency: "monthly", priority: 0.6 },
{ href: "/team", changeFrequency: "monthly", priority: 0.6 },
+ { href: "/join", changeFrequency: "monthly", priority: 0.6 },
{ href: "/volunteer", changeFrequency: "monthly", priority: 0.6 },
{ href: "/contact", changeFrequency: "yearly", priority: 0.5 },
] as const;
diff --git a/components/layout/Footer.tsx b/components/layout/Footer.tsx
deleted file mode 100644
index a5bf12e..0000000
--- a/components/layout/Footer.tsx
+++ /dev/null
@@ -1,107 +0,0 @@
-import Link from "next/link";
-import { footerNav } from "@/lib/constants";
-import { localizeHref, type Locale } from "@/lib/i18n/config";
-import type { SiteDictionary } from "@/lib/i18n/dictionary";
-
-type FooterDict = Pick
;
-
-// Maps a footer link's canonical href to its dictionary-covered nav
-// label, where one exists. Links without an entry here (Team,
-// LinkedIn, Instagram, "Get in Touch") keep their literal label from
-// lib/constants.ts.
-const DICT_KEY_BY_HREF: Record = {
- "/": "home",
- "/about": "about",
- "/team": "team",
- "/inspection": "inspection",
- "/fraud": "fraud",
- "/documents": "documents",
- "/research": "research",
- "/contact": "contact",
- "/join": "getInvolved",
-};
-
-const FOOTER_HEADING_KEY: Record = {
- Navigate: "navigate",
- Resources: "resources",
- Connect: "connect",
-};
-
-const FOOTER_LINK_KEY: Record = {
- LinkedIn: "linkedIn",
- Instagram: "instagram",
- "Get in Touch": "getInTouch",
-};
-
-export function Footer({ locale, dict }: { locale: Locale; dict: FooterDict }) {
- return (
-
-
-
- {/* Brand */}
-
-
-
VIN dicated
-
-
- {dict.footer.mission}
-
-
-
- {/* Nav columns */}
- {footerNav.map((col) => (
-
-
- {dict.footer.columns[FOOTER_HEADING_KEY[col.heading]] ?? col.heading}
-
-
- {col.links.map((link) => {
- const key = DICT_KEY_BY_HREF[link.href];
- const isExternal = "external" in link && link.external;
- const footerLinkKey = FOOTER_LINK_KEY[link.label];
- const label = footerLinkKey
- ? (dict.footer.links[footerLinkKey] ?? link.label)
- : key
- ? (dict.nav?.[key] ?? link.label)
- : link.label;
- return (
-
-
- {label}
-
-
- );
- })}
-
-
- ))}
-
-
-
-
- {dict.footer.copyright}
-
-
- {dict.footer.mission}
-
-
-
-
- );
-}
diff --git a/components/layout/LanguageSwitcher.tsx b/components/layout/LanguageSwitcher.tsx
deleted file mode 100644
index 9e54642..0000000
--- a/components/layout/LanguageSwitcher.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-"use client";
-
-import { useState, useRef, useEffect } from "react";
-import { usePathname, useRouter } from "next/navigation";
-import { locales, localeLabels, type Locale } from "@/lib/i18n/config";
-
-export function LanguageSwitcher({
- currentLocale,
- label = "Change language",
-}: {
- currentLocale: Locale;
- label?: string;
-}) {
- const [open, setOpen] = useState(false);
- const [triggerHovered, setTriggerHovered] = useState(false);
- const [hoveredLocale, setHoveredLocale] = useState(null);
- const ref = useRef(null);
- const pathname = usePathname();
- const router = useRouter();
-
- useEffect(() => {
- function onClickOutside(e: MouseEvent) {
- if (ref.current && !ref.current.contains(e.target as Node)) {
- setOpen(false);
- }
- }
- document.addEventListener("mousedown", onClickOutside);
- return () => document.removeEventListener("mousedown", onClickOutside);
- }, []);
-
- function switchTo(locale: Locale) {
- const segments = pathname.split("/");
- segments[1] = locale;
- router.push(segments.join("/"));
- setOpen(false);
- }
-
- return (
-
-
setOpen((o) => !o)}
- onMouseEnter={() => setTriggerHovered(true)}
- onMouseLeave={() => setTriggerHovered(false)}
- className="text-[0.85rem] font-semibold px-3 py-2 rounded-lg transition-colors duration-150 cursor-pointer"
- style={{
- color: "#fff",
- border: "1px solid var(--color-border)",
- background:
- open || triggerHovered ? "rgba(149,51,165,0.14)" : "transparent",
- }}
- aria-haspopup="listbox"
- aria-expanded={open}
- aria-label={label}
- >
- {localeLabels[currentLocale]}
-
-
- {open && (
-
- {locales.map((locale) => (
- switchTo(locale)}
- onMouseEnter={() => setHoveredLocale(locale)}
- onMouseLeave={() => setHoveredLocale(null)}
- className="w-full text-left px-4 py-2.5 text-[0.9rem] transition-colors duration-150 cursor-pointer"
- style={{
- color: "#fff",
- background:
- locale === currentLocale
- ? "rgba(149,51,165,0.16)"
- : locale === hoveredLocale
- ? "rgba(149,51,165,0.1)"
- : "transparent",
- fontWeight: locale === currentLocale ? 700 : 400,
- }}
- role="option"
- aria-selected={locale === currentLocale}
- >
- {localeLabels[locale]}
-
- ))}
-
- )}
-
- );
-}
diff --git a/components/layout/Nav.tsx b/components/layout/Nav.tsx
deleted file mode 100644
index 60ee917..0000000
--- a/components/layout/Nav.tsx
+++ /dev/null
@@ -1,563 +0,0 @@
-"use client";
-
-import { useState, useEffect, useRef, useCallback } from "react";
-import Image from "next/image";
-import Link from "next/link";
-import { usePathname } from "next/navigation";
-import { navLinks } from "@/lib/constants";
-import { localizeHref, type Locale } from "@/lib/i18n/config";
-import type { SiteDictionary } from "@/lib/i18n/dictionary";
-import { LanguageSwitcher } from "@/components/layout/LanguageSwitcher";
-
-// Types
-type NavLinkType = {
- label: string;
- href: string;
- standalone?: boolean;
- children?: readonly {
- label: string;
- href: string;
- description?: string;
- icon?: string;
- }[];
-};
-
-type NavDict = Pick;
-
-const DICT_KEY_BY_HREF: Record = {
- "/": "home",
- "/about": "about",
- "/about#mission": "aboutMission",
- "/about#story": "aboutFounder",
- "/about#vindicated-from": "aboutProvides",
- "/team": "team",
- "/inspection": "inspection",
- "/inspection#engine-diagram": "inspectionEngine",
- "/inspection#what-to-inspect": "inspectionChecks",
- "/inspection#where-to-get": "inspectionWhere",
- "/inspection#dealer-locators": "inspectionDealership",
- "/fraud": "fraud",
- "/fraud#red-flags": "fraudRedFlags",
- "/fraud#know-your-rights": "fraudRights",
- "/fraud#after": "fraudAfter",
- "/documents": "documents",
- "/volunteer": "volunteer",
- "/research": "research",
- "/contact": "contact",
- "/join": "getInvolved",
-};
-
-const DICT_KEY_BY_LABEL: Record = {
- "Who We Are": "aboutWhoWeAre",
- "What Is a PPI?": "inspectionPpi",
- Overview: "fraudOverview",
- "Learning Resources": "learningResources",
-};
-
-function labelFor(link: { label: string; href: string }, dict: NavDict) {
- const key = DICT_KEY_BY_LABEL[link.label] ?? DICT_KEY_BY_HREF[link.href];
- return key ? (dict.nav[key] ?? link.label) : link.label;
-}
-
-function expandLabel(dict: NavDict, label: string) {
- return dict.ui.expandSection.replace("{label}", label);
-}
-
-export function Nav({ locale, dict }: { locale: Locale; dict: NavDict }) {
- const [scrolled, setScrolled] = useState(false);
- const [menuOpen, setMenuOpen] = useState(false);
- const [activeDropdown, setActiveDropdown] = useState(null);
- const closeTimer = useRef | null>(null);
- const pathname = usePathname();
-
- const clearCloseTimer = () => {
- if (closeTimer.current) {
- clearTimeout(closeTimer.current);
- closeTimer.current = null;
- }
- };
-
- const closeMenu = useCallback(() => setMenuOpen(false), []);
-
- useEffect(() => {
- const onScroll = () => setScrolled(window.scrollY > 50);
- window.addEventListener("scroll", onScroll, { passive: true });
- return () => window.removeEventListener("scroll", onScroll);
- }, []);
-
- // Close mobile menu on route change
- useEffect(() => {
- closeMenu();
- }, [pathname, closeMenu]);
-
- // Lock body scroll when menu is open
- useEffect(() => {
- if (menuOpen) {
- document.body.style.overflow = "hidden";
- } else {
- document.body.style.overflow = "";
- }
- return () => {
- document.body.style.overflow = "";
- };
- }, [menuOpen]);
-
- const isActive = (href: string) => {
- const target = localizeHref(locale, href);
- return href === "/" ? pathname === target : pathname.startsWith(target);
- };
-
- return (
- <>
-
- {/* Logo */}
-
-
-
- VIN
- dicated
-
-
-
- {/* Desktop nav */}
-
-
- {navLinks.map((link) => (
- {
- clearCloseTimer();
- setActiveDropdown(link.href);
- }}
- onMouseLeave={() => {
- closeTimer.current = setTimeout(
- () => setActiveDropdown(null),
- 300,
- );
- }}
- onToggleClick={() => {
- clearCloseTimer();
- setActiveDropdown((current) =>
- current === link.href ? null : link.href,
- );
- }}
- />
- ))}
-
-
-
-
- {/* Hamburger / Close toggle */}
- setMenuOpen((v) => !v)}
- >
-
-
-
-
-
-
-
-
- {/* Mobile menu rendered outside to avoid z-index issues */}
-
- >
- );
-}
-
-// ── Mobile Menu ──────────────────────────────────────────────
-function MobileMenu({
- open,
- onClose,
- isActive,
- locale,
- dict,
-}: {
- open: boolean;
- onClose: () => void;
- isActive: (href: string) => boolean;
- locale: Locale;
- dict: NavDict;
-}) {
- const [expanded, setExpanded] = useState(null);
-
- // Reset expanded state when menu closes
- useEffect(() => {
- if (!open) setExpanded(null);
- }, [open]);
-
- return (
-
- {/* Scrollable link area, starts below the fixed nav bar */}
-
-
- {navLinks.map((link) => {
- const hasChildren = "children" in link && link.children;
- const isStandalone = (link as NavLinkType).standalone !== false;
- const active = isActive(link.href);
- const isExpanded = expanded === link.href;
-
- return (
-
- {/* Top-level link row */}
-
- {isStandalone ? (
-
- {labelFor(link, dict)}
-
- ) : (
-
- setExpanded(isExpanded ? null : link.href)
- }
- >
- {labelFor(link, dict)}
-
- )}
- {hasChildren && (
-
- setExpanded(isExpanded ? null : link.href)
- }
- >
-
-
-
-
- )}
-
-
- {/* Expandable sub-links */}
- {hasChildren && (
-
-
- {(link as NavLinkType).children!.map((child) => (
-
- {labelFor(child, dict)}
-
- ))}
-
-
- )}
-
- );
- })}
-
-
- {/* Language switcher, reachable on mobile too */}
-
-
-
-
-
- );
-}
-
-// ── Desktop Nav Item ────────────────────────────────────────
-function NavDropdownIcon({ icon }: { icon: string }) {
- const size = 20;
- switch (icon) {
- case "inspection":
- return (
-
-
-
-
- );
- case "fraud":
- return (
-
-
-
-
-
- );
- case "documents":
- return (
-
-
-
-
-
- );
- case "who":
- return (
-
-
-
-
- );
- case "mission":
- return (
-
-
-
-
-
- );
- case "founder":
- return (
-
-
-
-
- );
- case "provide":
- return (
-
-
-
-
-
- );
- default:
- return null;
- }
-}
-
-function DesktopNavItem({
- link,
- label,
- locale,
- dict,
- active,
- isOpen,
- onMouseEnter,
- onMouseLeave,
- onToggleClick,
-}: {
- link: NavLinkType;
- label: string;
- locale: Locale;
- dict: NavDict;
- active: boolean;
- isOpen: boolean;
- onMouseEnter: () => void;
- onMouseLeave: () => void;
- onToggleClick: () => void;
-}) {
- const isStandalone = link.standalone !== false;
- const sharedClassName =
- "text-[0.95rem] text-white hover:text-[var(--color-accent)] no-underline transition-colors duration-200 whitespace-nowrap focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-accent)] focus-visible:ring-offset-2 focus-visible:ring-offset-[#0d0a14] rounded-sm";
- const sharedStyle = {
- fontFamily: "var(--font-heading), Georgia, serif",
- fontWeight: active ? 600 : 400,
- } as const;
-
- return (
-
- {isStandalone ? (
-
- {label}
-
- ) : (
-
- {label}
-
- )}
- {link.children && isOpen && (
- c.description) ? 300 : 220,
- padding: link.children.some((c) => c.description) ? 8 : 6,
- }}
- >
- {link.children.map((child) =>
- child.description ? (
- {
- (e.currentTarget as HTMLAnchorElement).style.background =
- "rgba(149,51,165,0.12)";
- }}
- onMouseLeave={(e) => {
- (e.currentTarget as HTMLAnchorElement).style.background =
- "transparent";
- }}
- >
-
- {child.icon && }
-
-
-
- {labelFor(child, dict)}
-
-
- {child.description}
-
-
-
- ) : (
- {
- (e.currentTarget as HTMLAnchorElement).style.color =
- "var(--color-accent)";
- }}
- onMouseLeave={(e) => {
- (e.currentTarget as HTMLAnchorElement).style.color = "white";
- }}
- >
- {labelFor(child, dict)}
-
- ),
- )}
-
- )}
-
- );
-}
diff --git a/components/layout/SiteFooter.tsx b/components/layout/SiteFooter.tsx
new file mode 100644
index 0000000..b65ef25
--- /dev/null
+++ b/components/layout/SiteFooter.tsx
@@ -0,0 +1,89 @@
+import Image from "next/image";
+import Link from "next/link";
+import { localizeHref, type Locale } from "@/lib/i18n/config";
+import type { SiteDictionary } from "@/lib/i18n/dictionary";
+import { SOCIAL_URLS } from "@/lib/social";
+
+type FooterDict = Pick;
+
+export function SiteFooter({
+ locale,
+ dict,
+}: {
+ locale: Locale;
+ dict: FooterDict;
+}) {
+ const { nav, footer } = dict;
+ const href = (h: string) => localizeHref(locale, h);
+
+ const columns: { heading: string; links: { label: string; href: string }[] }[] = [
+ {
+ heading: footer.columns.organization,
+ links: [
+ { label: footer.links.aboutUs, href: href("/about") },
+ { label: nav.team, href: href("/team") },
+ { label: nav.projects, href: href("/research") },
+ { label: nav.getInvolved, href: href("/join") },
+ ],
+ },
+ {
+ heading: footer.columns.resources,
+ links: [
+ { label: nav.inspection, href: href("/inspection") },
+ { label: nav.fraud, href: href("/fraud") },
+ { label: nav.documents, href: href("/documents") },
+ ],
+ },
+ {
+ heading: footer.columns.connect,
+ links: [
+ { label: footer.links.linkedIn, href: SOCIAL_URLS.linkedin },
+ { label: footer.links.instagramUcla, href: SOCIAL_URLS.instagramUcla },
+ {
+ label: footer.links.instagramBerkeley,
+ href: SOCIAL_URLS.instagramBerkeley,
+ },
+ { label: footer.links.instagramUcsc, href: SOCIAL_URLS.instagramUcsc },
+ { label: footer.links.getInTouch, href: href("/join#contact") },
+ ],
+ },
+ ];
+
+ return (
+
+ );
+}
diff --git a/components/layout/SiteHeader.tsx b/components/layout/SiteHeader.tsx
new file mode 100644
index 0000000..d9fd903
--- /dev/null
+++ b/components/layout/SiteHeader.tsx
@@ -0,0 +1,217 @@
+"use client";
+
+import { useEffect, useRef, useState } from "react";
+import Image from "next/image";
+import Link from "next/link";
+import { usePathname, useRouter } from "next/navigation";
+import {
+ localeLabels,
+ locales,
+ localizeHref,
+ type Locale,
+} from "@/lib/i18n/config";
+import type { SiteDictionary } from "@/lib/i18n/dictionary";
+
+type HeaderDict = Pick;
+
+type NavItem = {
+ key: string;
+ href: string;
+ // Routes (without locale) that mark this top-level item as active.
+ match: string[];
+ children?: { key: string; href: string }[];
+};
+
+const NAV: NavItem[] = [
+ { key: "home", href: "/", match: ["/"] },
+ {
+ key: "about",
+ href: "/about",
+ match: ["/about", "/research"],
+ children: [
+ { key: "aboutWhoWeAre", href: "/about" },
+ { key: "aboutMission", href: "/about#mission" },
+ { key: "aboutFounder", href: "/about#story" },
+ { key: "aboutProvides", href: "/about#provide" },
+ { key: "projects", href: "/research" },
+ ],
+ },
+ { key: "team", href: "/team", match: ["/team"] },
+ {
+ key: "learningResources",
+ href: "/inspection",
+ match: ["/inspection", "/fraud", "/documents", "/map"],
+ children: [
+ { key: "inspection", href: "/inspection" },
+ { key: "fraud", href: "/fraud" },
+ { key: "documents", href: "/documents" },
+ // Dealer Map (/map) is hidden until its legal review is done.
+ ],
+ },
+];
+
+export function SiteHeader({
+ locale,
+ dict,
+}: {
+ locale: Locale;
+ dict: HeaderDict;
+}) {
+ const [open, setOpen] = useState(false);
+ const [langOpen, setLangOpen] = useState(false);
+ const langRef = useRef(null);
+ const pathname = usePathname();
+ const router = useRouter();
+
+ // Close menus whenever the route changes.
+ useEffect(() => {
+ setOpen(false);
+ setLangOpen(false);
+ }, [pathname]);
+
+ useEffect(() => {
+ if (!langOpen) return;
+ const onDown = (e: MouseEvent) => {
+ if (!langRef.current?.contains(e.target as Node)) setLangOpen(false);
+ };
+ const onKey = (e: KeyboardEvent) => {
+ if (e.key === "Escape") setLangOpen(false);
+ };
+ document.addEventListener("mousedown", onDown);
+ document.addEventListener("keydown", onKey);
+ return () => {
+ document.removeEventListener("mousedown", onDown);
+ document.removeEventListener("keydown", onKey);
+ };
+ }, [langOpen]);
+
+ const path = pathname.replace(`/${locale}`, "") || "/";
+ const isActive = (item: NavItem) =>
+ item.match.some((m) =>
+ m === "/" ? path === "/" : path === m || path.startsWith(`${m}/`),
+ );
+ const label = (key: string) => dict.nav[key] ?? key;
+ const href = (h: string) => localizeHref(locale, h);
+
+ function switchTo(next: Locale) {
+ const segments = pathname.split("/");
+ segments[1] = next;
+ router.push(segments.join("/") + window.location.hash);
+ setLangOpen(false);
+ }
+
+ return (
+
+
+
+
+ VINdicated
+
+
+
+
+
setLangOpen((o) => !o)}
+ >
+
+
+
+
+ {localeLabels[locale]}
+
+ {langOpen && (
+
+ {locales.map((l) => (
+
+ switchTo(l)}
+ >
+ {localeLabels[l]}
+
+
+ ))}
+
+ )}
+
+
setOpen((o) => !o)}
+ >
+
+ {open ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+ );
+}
diff --git a/components/sections/HomeCards.tsx b/components/sections/HomeCards.tsx
deleted file mode 100644
index 4a62ff0..0000000
--- a/components/sections/HomeCards.tsx
+++ /dev/null
@@ -1 +0,0 @@
-export { HomeCards } from "./HomeSections";
diff --git a/components/sections/HomeDashboard.tsx b/components/sections/HomeDashboard.tsx
deleted file mode 100644
index cde9002..0000000
--- a/components/sections/HomeDashboard.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import Image from "next/image";
-
-export function RoadScene() {
- const stars = [
- { top: 6, left: "8%", w: 2, delay: 0, dur: 2.2 },
- { top: 14, left: "25%", w: 1.5, delay: 0.8, dur: 2.8 },
- { top: 4, left: "55%", w: 2, delay: 1.2, dur: 1.9 },
- { top: 18, left: "75%", w: 1, delay: 0.3, dur: 3.1, color: "#b088cc" },
- { top: 8, left: "90%", w: 1.5, delay: 1.6, dur: 2.4 },
- ];
-
- const stripeDelays = [0, -0.56, -1.12, -1.68, -2.24];
-
- return (
-
- {/* Horizon glow */}
-
-
- {/* Stars */}
- {stars.map((s, i) => (
-
- ))}
-
- {/* Road */}
-
- {stripeDelays.map((delay, i) => (
-
- ))}
-
-
- {/* Driving car */}
-
-
-
-
- );
-}
diff --git a/components/sections/HomeFounder.tsx b/components/sections/HomeFounder.tsx
deleted file mode 100644
index 4f21339..0000000
--- a/components/sections/HomeFounder.tsx
+++ /dev/null
@@ -1 +0,0 @@
-export { HomeFounder } from "./HomeSections";
diff --git a/components/sections/HomeHero.tsx b/components/sections/HomeHero.tsx
deleted file mode 100644
index e784b4c..0000000
--- a/components/sections/HomeHero.tsx
+++ /dev/null
@@ -1,157 +0,0 @@
-"use client";
-import { useEffect, useRef } from "react";
-import { Button, FadeUp } from "@/components/ui";
-import { localizeHref, type Locale } from "@/lib/i18n/config";
-import type { HomeDict } from "@/lib/i18n/home-dict";
-// Animation config per stat -- not translatable content, so it lives here
-// rather than in the dict. Labels/cites always come from dict.hero.stats.
-const statConfig = [
- { id: "stat1", target: 1100, prefix: "$", suffix: "", dur: 1800 },
- { id: "stat2", target: 48, prefix: "", suffix: "%", dur: 1600 },
- { id: "stat3", target: 62.5, prefix: "", suffix: "%", dur: 1400 },
- { id: "stat4", target: 13, prefix: "", suffix: "%", dur: 1500 },
-];
-function animateCount(
- el: HTMLElement,
- target: number,
- prefix: string,
- suffix: string,
- duration: number,
-) {
- let startTime: number | null = null;
- const step = (now: number) => {
- if (!startTime) startTime = now;
- const progress = Math.min((now - startTime) / duration, 1);
- const eased = 1 - Math.pow(1 - progress, 3);
- el.textContent =
- prefix + Math.round(eased * target).toLocaleString() + suffix;
- if (progress < 1) requestAnimationFrame(step);
- };
- requestAnimationFrame(step);
-}
-export function HomeHero({
- locale,
- dict,
-}: {
- locale: Locale;
- dict: HomeDict;
-}) {
- const triggered = useRef(false);
- const stats = statConfig.map((s, i) => ({
- ...s,
- label: dict.hero.stats[i].label,
- cite: dict.hero.stats[i].cite,
- }));
- useEffect(() => {
- if (triggered.current) return;
- triggered.current = true;
- // Freeze each number's box to its final rendered width up front, so the
- // label beside it can never shift as the digits change during count-up.
- stats.forEach(({ id }) => {
- const el = document.getElementById(id);
- const wrap = el?.parentElement;
- if (wrap) wrap.style.width = `${wrap.getBoundingClientRect().width}px`;
- });
- setTimeout(() => {
- stats.forEach(({ id, target, prefix, suffix, dur }) => {
- const el = document.getElementById(id);
- if (el) animateCount(el, target, prefix, suffix, dur);
- });
- }, 600);
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
- return (
-
-
- {/* Glow */}
-
- {/* Left — text */}
-
-
-
- {dict.hero.titleLine1}
-
- {dict.hero.titleLine2}
-
- {dict.hero.titleEm}
-
-
-
-
- {dict.hero.subtitle}
-
-
-
-
-
- {dict.hero.ctaPrimary}
-
-
- {dict.hero.ctaSecondary}
-
-
-
-
- {/* Right — stats as stacked list */}
-
- {/* Stats */}
-
- {stats.map((s, i) => {
- const finalText = `${s.prefix}${Math.round(s.target).toLocaleString()}${s.suffix}`;
- return (
-
-
-
-
-
- {finalText}
-
-
- {s.prefix}0{s.suffix}
-
-
-
- {s.label} ({s.cite})
-
-
-
-
- );
- })}
-
-
-
-
- );
-}
diff --git a/components/sections/HomeQuote.tsx b/components/sections/HomeQuote.tsx
deleted file mode 100644
index ebd8c59..0000000
--- a/components/sections/HomeQuote.tsx
+++ /dev/null
@@ -1 +0,0 @@
-export { HomeQuote } from "./HomeSections";
diff --git a/components/sections/HomeSections.tsx b/components/sections/HomeSections.tsx
deleted file mode 100644
index 95c8831..0000000
--- a/components/sections/HomeSections.tsx
+++ /dev/null
@@ -1,137 +0,0 @@
-import Image from "next/image";
-import Link from "next/link";
-import {
- FadeUp,
- SectionTitle,
- Button,
-} from "@/components/ui";
-import { localizeHref, type Locale } from "@/lib/i18n/config";
-import type { HomeDict } from "@/lib/i18n/home-dict";
-
-// Non-translatable per-card config -- content comes from dict.cards.pillars.
-const pillarConfig = [{ href: "/inspection" }, { href: "/fraud" }];
-
-export function HomeCards({ locale, dict }: { locale: Locale; dict: HomeDict }) {
- const pillars = pillarConfig.map((p, i) => ({
- ...p,
- kicker: dict.cards.pillars[i].kicker,
- title: dict.cards.pillars[i].title,
- body: dict.cards.pillars[i].body,
- }));
-
- return (
-
-
-
-
- {dict.cards.titlePrefix} {dict.cards.titleEm}
-
-
-
- {pillars.map((p, i) => (
-
-
-
- {p.title}
-
-
- {p.body}
-
-
-
- ))}
-
-
-
-
- );
-}
-
-// Formerly the Wollstonecraft quote; now a tabling photo.
-// Keeps the same props so the home page doesn't need to change.
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-export function HomeQuote(_props: { dict: HomeDict }) {
- return (
-
- );
-}
-
-export function HomeFounder({ locale, dict }: { locale: Locale; dict: HomeDict }) {
- return (
-
-
-
-
-
- {dict.founder.titleLine1}
-
- {dict.founder.titleEm}
-
-
-
-
- {dict.founder.body1}
-
-
- {dict.founder.body2Prefix}
- {dict.founder.body2Bold}
-
-
-
-
- {dict.founder.cta}
-
-
-
- {/*
-
- */}
-
-
- );
-}
diff --git a/components/sections/PhotoCarousel.tsx b/components/sections/PhotoCarousel.tsx
deleted file mode 100644
index 774cc1e..0000000
--- a/components/sections/PhotoCarousel.tsx
+++ /dev/null
@@ -1,93 +0,0 @@
-"use client";
-
-import Image from "next/image";
-import { useEffect, useState } from "react";
-
-export type CarouselPhoto = {
- src: string;
- alt: string;
- /** CSS object-position, e.g. "center 70%" to keep faces in frame */
- position?: string;
-};
-
-export function PhotoCarousel({
- photos,
- interval = 5000,
- label,
-}: {
- photos: CarouselPhoto[];
- interval?: number;
- label: string;
-}) {
- const [active, setActive] = useState(0);
- const [paused, setPaused] = useState(false);
-
- useEffect(() => {
- if (paused || photos.length < 2) return;
- const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
- if (reduce) return;
- const id = setInterval(
- () => setActive((i) => (i + 1) % photos.length),
- interval,
- );
- return () => clearInterval(id);
- }, [paused, photos.length, interval]);
-
- return (
- setPaused(true)}
- onMouseLeave={() => setPaused(false)}
- onFocus={() => setPaused(true)}
- onBlur={() => setPaused(false)}
- >
- {photos.map((photo, i) => {
- const isActive = i === active;
- return (
-
-
-
- );
- })}
-
- {photos.length > 1 && (
-
- {photos.map((photo, i) => (
- setActive(i)}
- aria-label={`Show photo ${i + 1} of ${photos.length}`}
- aria-current={i === active}
- className="h-2 rounded-full bg-white transition-all duration-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
- style={{
- width: i === active ? "24px" : "8px",
- opacity: i === active ? 1 : 0.5,
- }}
- />
- ))}
-
- )}
-
- );
-}
diff --git a/components/sections/RedFlagField.tsx b/components/sections/RedFlagField.tsx
deleted file mode 100644
index 542da8b..0000000
--- a/components/sections/RedFlagField.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-"use client";
-
-import { useState } from "react";
-
-const redFlags = [
- {
- label: "Too-Good-To-Be-True Pricing",
- trigger: "Too Good to Be True Pricing",
- body: "Dealers advertise a price that already includes a stack of rebates and discounts: military, teacher, loyalty, recent grad, and more. Most buyers will not actually qualify for most of them. The price online is built to get you in the door, not to be the price you pay.",
- script: "Ask for the out-the-door price in writing before you go in, and ask exactly which discounts you qualify for.",
- },
- {
- label: "The Disappearing Discounts",
- trigger: "The Disappearing Discounts Script",
- body: "At the desk, the salesperson asks a series of qualifying questions: are you a college grad, military, a local resident, trading in a car. Each no crosses off a discount. By the end, your price has climbed by thousands, even though you were told you qualify for the manufacturer's rebate.",
- script: "Ask to see the original advertised price next to the final price, with every line item that changed and why.",
- },
- {
- label: "Bogus Accessories",
- trigger: "Bogus Accessories and Coatings",
- body: "Wheel locks, splash guards, paint protectant, and similar add-ons get added to the price even if you never asked for them. If the dealer says it is already on the car, that is a negotiating point, not a reason to pay for it.",
- script: "Ask the dealer to remove anything you did not request, or to lower the price to reflect it.",
- },
- {
- label: "Made-Up Fees",
- trigger: "Made-Up Fees",
- body: "A full tank of gas, a reconditioning fee, a CPO fee, a delivery or clean up fee: these are usually already built into the price by the manufacturer. Charging for them again is just an extra markup with an official-sounding name.",
- script: "Ask which fees are required by law and which ones are made up, then ask for those removed.",
- },
- {
- label: "Double-Charged Destination Fee",
- trigger: "The Double-Charged Destination Fee",
- body: "Destination, also called freight, is already listed on the window sticker above the MSRP. A dishonest dealer will quote you a price that already includes it, then add it again later as a separate fee. If you see destination broken out on its own line, you are being charged for it twice.",
- script: "Ask whether destination is already included in the price you were quoted, and ask to see it removed if it shows up again.",
- },
-];
-
-export function RedFlagField() {
- const [activeIndex, setActiveIndex] = useState(null);
-
- function selectFlag(i: number) {
- setActiveIndex((cur) => (cur === i ? null : i));
- }
-
- const active = activeIndex !== null ? redFlags[activeIndex] : null;
-
- return (
-
-
-
-
- {redFlags.map((flag, i) => (
-
selectFlag(i)}
- >
-
-
{flag.label}
-
- ))}
-
-
- {!active &&
Tap any flag above to read it.
}
-
-
- {active && (
-
-
{active.trigger}
-
{active.body}
-
- What to say: {active.script}
-
-
- )}
-
-
- );
-}
diff --git a/components/sections/RoadScene.tsx b/components/sections/RoadScene.tsx
deleted file mode 100644
index cc4955e..0000000
--- a/components/sections/RoadScene.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import Image from "next/image";
-
-export function RoadScene() {
- const stars = [
- { top: 6, left: "8%", w: 2, delay: 0, dur: 2.2 },
- { top: 14, left: "25%", w: 1.5, delay: 0.8, dur: 2.8 },
- { top: 4, left: "55%", w: 2, delay: 1.2, dur: 1.9 },
- { top: 18, left: "75%", w: 1, delay: 0.3, dur: 3.1, color: "#b088cc" },
- { top: 8, left: "90%", w: 1.5, delay: 1.6, dur: 2.4 },
- ];
-
- const stripeDelays = [0, -0.7448, -1.4896, -2.2344, -2.9792];
-
- return (
-
- {/* Horizon glow */}
-
-
- {/* Stars */}
- {stars.map((s, i) => (
-
- ))}
-
- {/* Road */}
-
- {stripeDelays.map((delay, i) => (
-
- ))}
-
-
- {/* Driving car */}
-
-
-
-
- );
-}
diff --git a/components/sections/ScamNotebook.tsx b/components/sections/ScamNotebook.tsx
deleted file mode 100644
index 6527ad7..0000000
--- a/components/sections/ScamNotebook.tsx
+++ /dev/null
@@ -1,138 +0,0 @@
-"use client";
-
-import { useEffect, useRef, useState } from "react";
-import { Patrick_Hand } from "next/font/google";
-
-const patrickHand = Patrick_Hand({ subsets: ["latin"], weight: "400" });
-
-const scamSteps = [
- { strong: "Document everything immediately.", text: "Dates, times, names. Save all texts, emails, and contracts." },
- { strong: "File with your state DMV.", text: "Most states have consumer protection divisions for automotive fraud." },
- { strong: "File with the FTC.", text: "reportfraud.ftc.gov: complaints build the database used to pursue enforcement." },
- { strong: "Contact the manufacturer.", text: "Franchised dealerships have parent oversight. They take complaints seriously." },
- { strong: "Consider a consumer protection attorney.", text: "Many work on contingency; you pay nothing upfront." },
- { strong: "Leave an honest public review.", text: "Google, Yelp, BBB. You're protecting the next person." },
-];
-
-type Step = (typeof scamSteps)[number];
-
-function FlipClone({
- step,
- num,
- onDone,
-}: {
- step: Step;
- num: number;
- onDone: () => void;
-}) {
- const [flipped, setFlipped] = useState(false);
-
- useEffect(() => {
- const raf = requestAnimationFrame(() => setFlipped(true));
- return () => cancelAnimationFrame(raf);
- }, []);
-
- return (
-
-
{num}.
-
{step.strong}
-
{step.text}
-
- );
-}
-
-export function ScamNotebook() {
- const [index, setIndex] = useState(0);
- const [cloneId, setCloneId] = useState(null);
- const idRef = useRef(0);
-
- function flip() {
- if (cloneId !== null) return;
- idRef.current += 1;
- setCloneId(idRef.current);
- }
-
- function handleCloneDone() {
- setIndex((i) => (i >= scamSteps.length - 1 ? 0 : i + 1));
- setCloneId(null);
- }
-
- const current = scamSteps[index];
- const nextIndex = (index + 1) % scamSteps.length;
- const upcoming = scamSteps[nextIndex];
- const isLast = index === scamSteps.length - 1;
-
- return (
-
-
-
-
-
- {Array.from({ length: 11 }).map((_, i) => (
-
- ))}
-
-
-
-
-
{nextIndex + 1}.
-
{upcoming.strong}
-
{upcoming.text}
-
-
-
-
{index + 1}.
-
{current.strong}
-
{current.text}
-
- {isLast ? "tap to start over" : "tap to flip \u2192"}
-
-
-
- {cloneId !== null && (
-
- )}
-
-
-
- {scamSteps.map((_, i) => (
-
- ))}
-
-
-
- );
-}
diff --git a/components/sections/StoryCarousel.tsx b/components/sections/StoryCarousel.tsx
deleted file mode 100644
index 6b1a14d..0000000
--- a/components/sections/StoryCarousel.tsx
+++ /dev/null
@@ -1,151 +0,0 @@
-import { Fragment } from "react";
-import Image from "next/image";
-
-type Strike = { num?: string; label?: string; body?: string[] };
-
-// Desktop-only art beside each stop. Strike 1 has a real photo; the
-// other two don't have one yet, so they get a small line-icon that
-// echoes a concrete detail from that strike's story instead of a
-// generic "image coming soon" placeholder.
-function BlockedMessageIcon() {
- return (
-
-
-
-
- );
-}
-
-function LockedDrawerIcon() {
- return (
-
-
-
-
-
- );
-}
-
-function StopArt({ index }: { index: number }) {
- if (index === 0) {
- return (
-
- );
- }
- return (
-
- {index === 1 ? : }
-
- );
-}
-
-// Each strike is a stop on the same road: a dot, a dashed run of
-// lane-marking down to the next one, same grammar as the route icon
-// used elsewhere on the site. All three read at once, in order.
-// A desktop-only third column carries a small image/icon per stop —
-// the same CSS grid rows keep it vertically locked to its strike.
-export function StoryCarousel({ strikes }: { strikes: Strike[] }) {
- return (
-
- {strikes.map((s, i) => {
- const isLast = i === strikes.length - 1;
- const pad = isLast ? "" : "pb-14 max-md:pb-10";
- return (
-
-
-
- {!isLast && (
-
- )}
-
-
-
-
-
- Strike {i + 1} of {strikes.length}:{" "}
-
- {s.label}
-
-
- {s.body?.map((p, j) => (
-
- {p}
-
- ))}
-
-
-
-
-
- );
- })}
-
- );
-}
diff --git a/components/sections/StudyCard.tsx b/components/sections/StudyCard.tsx
deleted file mode 100644
index 59a896d..0000000
--- a/components/sections/StudyCard.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-"use client";
-
-import { Tag } from "@/components/ui";
-
-type Study = {
- meta: string;
- title: string;
- body: string;
- rq?: string | null;
- tags: string[];
-};
-
-export function StudyCard({ study }: { study: Study }) {
- return (
- {
- (e.currentTarget as HTMLDivElement).style.borderColor =
- "var(--color-vivid)";
- }}
- onMouseLeave={(e) => {
- (e.currentTarget as HTMLDivElement).style.borderColor =
- "var(--color-border)";
- }}
- >
-
- {study.meta}
-
-
- {study.title}
-
-
{study.body}
- {study.rq && (
-
- Research questions: {study.rq}
-
- )}
-
- {study.tags.map((t) => (
- {t}
- ))}
-
-
- );
-}
diff --git a/components/sections/TeamDirectory.tsx b/components/sections/TeamDirectory.tsx
deleted file mode 100644
index 4f1be14..0000000
--- a/components/sections/TeamDirectory.tsx
+++ /dev/null
@@ -1,284 +0,0 @@
-"use client";
-
-import { useMemo, useState } from "react";
-import Image from "next/image";
-import { FadeUp } from "@/components/ui";
-
-export type Social = {
- platform: "linkedin" | "github" | "instagram" | "website";
- href: string;
-};
-
-export type Chapter = "leadership" | "ucla" | "ucb" | "ucsc";
-
-export type TeamMemberView = {
- name: string;
- position: string;
- bio: string;
- // Sort key, computed by the page from the member's *English* position
- // via lib/team-rank.ts's positionRank() so the ordering is identical
- // in every locale -- not derived from the translated `position` text
- // above, which positionRank's English-only regexes wouldn't match.
- rank: number;
- major?: string;
- chapter: Chapter;
- photo: string | null;
- socials?: Social[];
-};
-
-const CHAPTER_OPTIONS: { value: "all" | Chapter; label: string }[] = [
- { value: "all", label: "All" },
- { value: "leadership", label: "Leadership" },
- { value: "ucla", label: "UCLA" },
- { value: "ucb", label: "UC Berkeley" },
- { value: "ucsc", label: "UC Santa Cruz" },
-];
-
-// No mascot for "leadership" -- it isn't tied to a single campus.
-const CHAPTER_MASCOT: Partial> = {
- ucla: "/ucla-mascot.png",
- ucb: "/berkeley-mascot.png",
- ucsc: "/ucsc-mascot.png",
-};
-
-// No school name for "leadership" -- it isn't tied to a single campus.
-const CHAPTER_SCHOOL: Partial> = {
- ucla: "UCLA",
- ucb: "UC Berkeley",
- ucsc: "UC Santa Cruz",
-};
-
-function Initials({ name }: { name: string }) {
- const initials = name
- .split(" ")
- .filter(Boolean)
- .slice(0, 2)
- .map((w) => w[0])
- .join("")
- .toUpperCase();
- return (
-
-
- {initials}
-
-
- );
-}
-
-function SocialIcon({ platform }: { platform: Social["platform"] }) {
- const size = 18;
- switch (platform) {
- case "linkedin":
- return (
-
-
-
- );
- case "github":
- return (
-
-
-
- );
- case "instagram":
- return (
-
-
-
- );
- case "website":
- return (
-
-
-
-
- );
- }
-}
-
-export function TeamDirectory({ members }: { members: TeamMemberView[] }) {
- const [query, setQuery] = useState("");
- const [chapter, setChapter] = useState<"all" | Chapter>("all");
-
- const sorted = useMemo(
- () => [...members].sort((a, b) => a.rank - b.rank),
- [members],
- );
-
- const filtered = useMemo(() => {
- const q = query.trim().toLowerCase();
- return sorted.filter((m) => {
- if (chapter !== "all" && m.chapter !== chapter) return false;
- if (!q) return true;
- return (
- m.name.toLowerCase().includes(q) ||
- (m.major?.toLowerCase().includes(q) ?? false) ||
- m.position.toLowerCase().includes(q)
- );
- });
- }, [sorted, query, chapter]);
-
- return (
-
- {/* Search + school filter */}
-
-
setQuery(e.target.value)}
- placeholder="Search the team by name, major, or role"
- aria-label="Search the team"
- className="flex-1 min-w-[240px] text-[0.95rem] px-4 py-3 rounded-lg outline-none transition-colors duration-150 focus:border-[var(--color-accent)]"
- style={{
- background: "var(--color-bg-surface)",
- border: "1px solid var(--color-border)",
- color: "#fff",
- }}
- />
-
- {CHAPTER_OPTIONS.map((opt) => (
- setChapter(opt.value)}
- aria-pressed={chapter === opt.value}
- className="text-[0.85rem] font-semibold px-4 py-3 rounded-lg cursor-pointer transition-colors duration-150 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2"
- style={{
- color: "#fff",
- border: "1px solid var(--color-border)",
- background:
- chapter === opt.value
- ? "rgba(149,51,165,0.16)"
- : "transparent",
- outlineColor:
- chapter === opt.value ? "var(--color-accent)" : undefined,
- }}
- >
- {opt.label}
-
- ))}
-
-
-
- {filtered.length === 0 ? (
-
- No one matches that search.
-
- ) : (
-
- {filtered.map((member) => {
- const mascot = CHAPTER_MASCOT[member.chapter];
- const school = CHAPTER_SCHOOL[member.chapter];
- const label = member.major
- ? school
- ? `${member.major}, ${school}`
- : member.major
- : school;
- return (
-
-
- {/* Photo */}
-
- {member.photo ? (
-
-
-
- ) : (
-
- )}
-
-
- {/* Info */}
-
-
- {member.name}
-
-
- {member.position}
-
-
- {label && (
-
- {label}
-
- )}
- {mascot && (
-
- )}
-
-
- {member.bio}
-
-
-
- {/* Socials */}
- {member.socials && member.socials.length > 0 && (
-
- {member.socials.map((s) => (
-
-
-
- ))}
-
- )}
-
-
- );
- })}
-
- )}
-
- );
-}
diff --git a/components/sections/WollstonecraftQuotes.tsx b/components/sections/WollstonecraftQuotes.tsx
deleted file mode 100644
index 9230700..0000000
--- a/components/sections/WollstonecraftQuotes.tsx
+++ /dev/null
@@ -1,125 +0,0 @@
-"use client";
-
-import { useCallback, useEffect, useRef, useState } from "react";
-
-const QUOTES: { quote: string; source: string }[] = [
- {
- quote:
- "Strengthen the female mind by enlarging it, and there will be an end to blind obedience.",
- source: "A Vindication of the Rights of Woman, 1792",
- },
- {
- quote:
- "My own sex, I hope, will excuse me, if I treat them like rational creatures, instead of flattering their fascinating graces, and viewing them as if they were in a state of perpetual childhood, unable to stand alone.",
- source: "A Vindication of the Rights of Woman",
- },
- {
- quote:
- "It is vain to expect virtue from women till they are in some degree independent of men.",
- source: "A Vindication of the Rights of Woman",
- },
- {
- quote:
- "All the sacred rights of humanity are violated by insisting on blind obedience.",
- source: "A Vindication of the Rights of Woman",
- },
- {
- quote: "It is justice, not charity, that is wanting in the world!",
- source: "A Vindication of the Rights of Woman",
- },
- {
- quote:
- "I do not wish them [women] to have power over men; but over themselves.",
- source: "A Vindication of the Rights of Woman",
- },
-];
-
-const AUTO_ADVANCE_MS = 6000;
-const FADE_MS = 250;
-
-export function WollstonecraftQuotes() {
- const [index, setIndex] = useState(0);
- const [visible, setVisible] = useState(true);
- const timerRef = useRef | null>(null);
-
- const goTo = useCallback((next: number) => {
- setVisible(false);
- setTimeout(() => {
- setIndex(next);
- setVisible(true);
- }, FADE_MS);
- }, []);
-
- const advance = useCallback(() => {
- setIndex((current) => {
- const next = (current + 1) % QUOTES.length;
- goTo(next);
- return current;
- });
- }, [goTo]);
-
- // Auto-advance on a timer; resets whenever the index changes,
- // so a manual click pushes the next auto-advance back out.
- useEffect(() => {
- if (timerRef.current) clearInterval(timerRef.current);
- timerRef.current = setInterval(advance, AUTO_ADVANCE_MS);
- return () => {
- if (timerRef.current) clearInterval(timerRef.current);
- };
- }, [index, advance]);
-
- const current = QUOTES[index];
-
- return (
-
-
goTo((index + 1) % QUOTES.length)}
- className="text-left w-full bg-transparent border-none p-0 cursor-pointer"
- aria-label="Show next Wollstonecraft quote"
- >
-
- “{current.quote}”
-
-
- Mary Wollstonecraft, {current.source}
-
-
-
-
- {QUOTES.map((_, i) => (
- goTo(i)}
- aria-label={`Go to quote ${i + 1} of ${QUOTES.length}`}
- className="rounded-full transition-all cursor-pointer"
- style={{
- width: i === index ? 20 : 6,
- height: 6,
- transitionDuration: `${FADE_MS}ms`,
- background:
- i === index ? "var(--color-accent)" : "rgba(149,51,165,0.25)",
- }}
- />
- ))}
-
-
- );
-}
diff --git a/components/sections/about/FounderStory.tsx b/components/sections/about/FounderStory.tsx
new file mode 100644
index 0000000..40257cc
--- /dev/null
+++ b/components/sections/about/FounderStory.tsx
@@ -0,0 +1,47 @@
+"use client";
+
+import type { AboutPageDict } from "@/lib/i18n/dictionary";
+import { useInView } from "../shared/useInView";
+
+// Sticky intro on the left, strike cards that fade in as they scroll past.
+export function FounderStory({ dict }: { dict: AboutPageDict["story"] }) {
+ return (
+
+
+
+
{dict.title}
+
{dict.body}
+
+ {dict.quote}
+ {dict.quoteCite}
+
+
+
+ {dict.strikes.map((s) => (
+
+ ))}
+
+
+
+ );
+}
+
+function StrikeCard({
+ strike,
+}: {
+ strike: AboutPageDict["story"]["strikes"][number];
+}) {
+ const [ref, inView] = useInView(0.35);
+ return (
+
+
+
+ {strike.n}
+
+ {strike.tag}
+
+ {strike.title}
+ {strike.body}
+
+ );
+}
diff --git a/components/sections/about/FounderVideo.tsx b/components/sections/about/FounderVideo.tsx
new file mode 100644
index 0000000..33c283d
--- /dev/null
+++ b/components/sections/about/FounderVideo.tsx
@@ -0,0 +1,58 @@
+"use client";
+
+import { useRef, useState } from "react";
+import type { AboutPageDict } from "@/lib/i18n/dictionary";
+
+export function FounderVideo({ dict }: { dict: AboutPageDict["video"] }) {
+ const videoRef = useRef(null);
+ const [playing, setPlaying] = useState(false);
+
+ function play() {
+ const v = videoRef.current;
+ if (!v) return;
+ setPlaying(true);
+ v.play();
+ v.focus();
+ }
+
+ return (
+
+
+
+
{
+ setPlaying(false);
+ videoRef.current?.load();
+ }}
+ >
+
+
+
+
+
+
+
+
+
+ {dict.length}
+
+
+
+
+
{dict.title}
+
{dict.body}
+
+ {dict.name}
+ {dict.role}
+
+
+
+
+ );
+}
diff --git a/components/sections/about/MissionPillars.tsx b/components/sections/about/MissionPillars.tsx
new file mode 100644
index 0000000..cab02e0
--- /dev/null
+++ b/components/sections/about/MissionPillars.tsx
@@ -0,0 +1,36 @@
+import type { AboutPageDict } from "@/lib/i18n/dictionary";
+
+const ICONS = [
+ ,
+
+
+
+ ,
+ ,
+];
+
+export function MissionPillars({ dict }: { dict: AboutPageDict["mission"] }) {
+ return (
+
+
+
+
{dict.title}
+
{dict.body}
+
+
+ {dict.items.map((item, i) => (
+
+
+
+ {ICONS[i]}
+
+
+
{item.title}
+
{item.body}
+
+ ))}
+
+
+
+ );
+}
diff --git a/components/sections/about/QuoteBand.tsx b/components/sections/about/QuoteBand.tsx
new file mode 100644
index 0000000..83a8713
--- /dev/null
+++ b/components/sections/about/QuoteBand.tsx
@@ -0,0 +1,16 @@
+export function QuoteBand({ text, cite }: { text: string; cite: string }) {
+ return (
+
+
+
+
+ {text}
+
+
+ {cite}
+
+
+
+
+ );
+}
diff --git a/components/sections/about/WhatWeProvide.tsx b/components/sections/about/WhatWeProvide.tsx
new file mode 100644
index 0000000..e8e381e
--- /dev/null
+++ b/components/sections/about/WhatWeProvide.tsx
@@ -0,0 +1,52 @@
+import Link from "next/link";
+import type { AboutPageDict } from "@/lib/i18n/dictionary";
+
+const ICONS = [
+ ,
+ ,
+ ,
+ ,
+];
+
+export function WhatWeProvide({
+ dict,
+ projectsHref,
+}: {
+ dict: AboutPageDict["provide"];
+ projectsHref: string;
+}) {
+ const last = dict.items.length - 1;
+ return (
+
+
+
+
{dict.title}
+
{dict.body}
+
+
+ {dict.items.map((item, i) => (
+
+
+
+ {ICONS[i]}
+
+
+
{item.title}
+
+ {item.body}
+ {i === last && (
+ <>
+ {" "}
+
+ {dict.projectsLink}
+
+ >
+ )}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/components/sections/about/ZoomSlideshow.tsx b/components/sections/about/ZoomSlideshow.tsx
new file mode 100644
index 0000000..c84f66c
--- /dev/null
+++ b/components/sections/about/ZoomSlideshow.tsx
@@ -0,0 +1,127 @@
+"use client";
+
+import { useEffect, useRef, useState } from "react";
+import Image from "next/image";
+import type { AboutPageDict } from "@/lib/i18n/dictionary";
+import { usePrefersReducedMotion } from "../shared/usePrefersReducedMotion";
+
+const PHOTOS = [
+ { src: "/images/about/img_4424_2.webp", position: "center 70%" },
+ { src: "/images/about/berkeley-tabling-1.webp", position: "center 45%" },
+ { src: "/images/about/berkeley-tabling-2.webp", position: "center 40%" },
+ { src: "/images/about/img_8120.webp", position: "center 55%" },
+ { src: "/images/about/img_4422_2.webp", position: "center 72%" },
+ { src: "/images/about/img_8112.webp", position: "center 50%" },
+ { src: "/images/about/img_8126.webp", position: "center 50%" },
+ { src: "/images/about/img_4423_2.webp", position: "center 70%" },
+ { src: "/images/about/img_8103.webp", position: "center 45%" },
+ { src: "/images/about/img_8130.webp", position: "center 50%" },
+];
+
+const INTERVAL_MS = 3200;
+const pad = (n: number) => String(n).padStart(2, "0");
+
+// A photo frame that grows to full-bleed as you scroll through it, while
+// the photos cross-fade on a timer.
+export function ZoomSlideshow({ dict }: { dict: AboutPageDict["zoom"] }) {
+ const reduce = usePrefersReducedMotion();
+ const sectionRef = useRef(null);
+ const frameRef = useRef(null);
+ const [index, setIndex] = useState(0);
+ const [userPaused, setUserPaused] = useState(false);
+ const paused = userPaused || reduce;
+
+ useEffect(() => {
+ if (paused) return;
+ const t = setInterval(
+ () => setIndex((i) => (i + 1) % PHOTOS.length),
+ INTERVAL_MS,
+ );
+ return () => clearInterval(t);
+ }, [paused]);
+
+ useEffect(() => {
+ const section = sectionRef.current;
+ const frame = frameRef.current;
+ if (!section || !frame) return;
+ if (reduce) {
+ frame.style.removeProperty("--p");
+ return;
+ }
+ let ticking = false;
+ const update = () => {
+ ticking = false;
+ const r = section.getBoundingClientRect();
+ const total = r.height - window.innerHeight;
+ const p = Math.min(1, Math.max(0, -r.top / (total * 0.7)));
+ frame.style.setProperty("--p", p.toFixed(4));
+ };
+ const onScroll = () => {
+ if (!ticking) {
+ ticking = true;
+ requestAnimationFrame(update);
+ }
+ };
+ update();
+ window.addEventListener("scroll", onScroll, { passive: true });
+ window.addEventListener("resize", update);
+ return () => {
+ window.removeEventListener("scroll", onScroll);
+ window.removeEventListener("resize", update);
+ };
+ }, [reduce]);
+
+ return (
+
+
+
+
+ {PHOTOS.map((p, i) => (
+
+ ))}
+
+
+
+
+ {dict.titleLine1}
+
+ {dict.titleLine2}
+
+
{dict.body}
+
+
+
+ {pad(index + 1)} / {pad(PHOTOS.length)}
+
+
setUserPaused((v) => !v)}
+ >
+ {paused ? (
+
+
+
+ ) : (
+
+
+
+
+ )}
+
+
+
+
+
+ );
+}
diff --git a/components/sections/fraud/AprCalculator.tsx b/components/sections/fraud/AprCalculator.tsx
new file mode 100644
index 0000000..8bb266b
--- /dev/null
+++ b/components/sections/fraud/AprCalculator.tsx
@@ -0,0 +1,184 @@
+"use client";
+
+import { useState, type CSSProperties } from "react";
+import type { FraudPageDict } from "@/lib/i18n/dictionary";
+import { formatMoney } from "./money";
+
+type Dict = FraudPageDict["apr"];
+
+const PRINCIPAL = 15000;
+const TERMS = [36, 48, 60, 72];
+const MIN = 3;
+const MAX = 30;
+
+const monthly = (apr: number, n: number) => {
+ const r = apr / 1200;
+ return r === 0 ? PRINCIPAL / n : (PRINCIPAL * r) / (1 - Math.pow(1 + r, -n));
+};
+const pct = (v: number) => ((Math.min(MAX, Math.max(MIN, v)) - MIN) / (MAX - MIN)) * 100;
+
+// California caps the dealer's markup over the lender's approved rate:
+// 2 points on loans over 60 months, 2.5 points otherwise.
+const markupCap = (term: number) => (term > 60 ? 2 : 2.5);
+
+export function AprCalculator({ dict, locale }: { dict: Dict; locale: string }) {
+ const [rate, setRate] = useState(7);
+ const [term, setTerm] = useState(60);
+ const [buyInput, setBuyInput] = useState("7");
+ const money = (n: number) => formatMoney(n, locale);
+ const fmt1 = (n: number) =>
+ n.toLocaleString(locale, { minimumFractionDigits: 1, maximumFractionDigits: 1 });
+
+ const buy = Math.min(25, Math.max(2, parseFloat(buyInput) || 7));
+ const points = markupCap(term);
+ const cap = buy + points;
+ const mo = monthly(rate, term);
+ const tot = mo * term;
+ const interest = tot - PRINCIPAL;
+ const baseInterest = monthly(buy, term) * term - PRINCIPAL;
+ const over = rate > cap + 1e-9;
+ const marked = !over && rate > buy + 1e-9;
+ const close = Math.abs(pct(cap) - pct(buy)) < 22;
+
+ const stepBuy = (d: number) => setBuyInput(String(Math.min(25, Math.max(2, buy + d))));
+
+ return (
+
+
+
+ {dict.rateLabel}
+
+
+ {fmt1(rate)}%
+
+
+
setRate(+e.target.value)}
+ />
+
+
+
+ {dict.approval}
+
+
+
+ {dict.capMark.replace("{rate}", fmt1(cap))}
+
+
+
+ {MIN}%
+ {MAX}%
+
+
+
+
+
+ {dict.termLabel}
+
+
+ {TERMS.map((n) => (
+ setTerm(n)}
+ >
+ {dict.termOption.replace("{n}", String(n))}
+
+ ))}
+
+
+
+
+ {dict.approvedLabel}
+
+
+ stepBuy(-0.5)}>
+ −
+
+ setBuyInput(e.target.value)}
+ onBlur={() => setBuyInput(String(buy))}
+ />
+ %
+ stepBuy(0.5)}>
+ +
+
+
+
+
+
+ {dict.hint}
+
+
+
+
+ {dict.monthly}
+ {dict.perMonth.replace("{amount}", money(mo))}
+
+
+
+ {dict.interest}
+ {money(interest)}
+
+
+ {dict.totalCost}
+ {money(tot)}
+
+
+
+
+
+
+
+
+
+ {dict.car}
+
+
+
+ {dict.interestKey}
+
+
+
+ {over ? (
+ <>
+ {dict.overTitle} {" "}
+ {dict.over
+ .replace("{buy}", fmt1(buy))
+ .replace("{points}", String(points))
+ .replace("{term}", String(term))
+ .replace("{cap}", fmt1(cap))}
+ >
+ ) : marked ? (
+ <>
+ {dict.markupTitle} {" "}
+ {dict.markup.replace("{amount}", money(interest - baseInterest)).replace("{buy}", fmt1(buy))}
+ >
+ ) : (
+ <>
+ {dict.okTitle} {dict.ok}
+ >
+ )}
+
+
+
+ );
+}
diff --git a/components/sections/fraud/FeeReceipt.tsx b/components/sections/fraud/FeeReceipt.tsx
new file mode 100644
index 0000000..8ef9ca5
--- /dev/null
+++ b/components/sections/fraud/FeeReceipt.tsx
@@ -0,0 +1,104 @@
+"use client";
+
+import { useState } from "react";
+import type { FraudPageDict } from "@/lib/i18n/dictionary";
+import { formatMoney } from "./money";
+
+type Dict = FraudPageDict["receipt"];
+type Category = "req" | "neg" | "opt" | "red";
+
+// Amounts and categories for each receipt line, in dictionary order.
+const LINES: [number, Category][] = [
+ [28500, "neg"], [1395, "req"], [2500, "red"], [495, "red"], [299, "red"],
+ [199, "red"], [895, "opt"], [2195, "opt"], [795, "opt"], [85, "req"],
+ [7, "req"], [3325, "req"], [620, "req"],
+];
+const CAT_TAG: Record = {
+ req: "sev-easy",
+ neg: "sev-know",
+ opt: "sev-watch",
+ red: "sev-red",
+};
+const canDrop = (c: Category) => c === "red" || c === "opt";
+
+export function FeeReceipt({ dict, locale }: { dict: Dict; locale: string }) {
+ const [open, setOpen] = useState(null);
+ const [strip, setStrip] = useState(false);
+ const money = (n: number) => formatMoney(n, locale);
+
+ let total = 0;
+ let saved = 0;
+ LINES.forEach(([amt, c]) => {
+ if (strip && canDrop(c)) saved += amt;
+ else total += amt;
+ });
+
+ return (
+ <>
+
+ {(Object.keys(CAT_TAG) as Category[]).map((c) => (
+
+
+ {dict.categories[c]}
+
+ ))}
+
+
+
+
+ {dict.heading}
+ {dict.sub}
+
+
+ {dict.lines.map((l, i) => {
+ const [amt, c] = LINES[i];
+ const isOpen = open === i;
+ const gone = strip && canDrop(c);
+ return (
+
+ setOpen(isOpen ? null : i)}
+ >
+
+
+ {l.name}
+ ({dict.categories[c]})
+
+ {money(amt)}
+
+
+
+
+
+ {dict.categories[c]}
+
+
+ {l.short} {l.long}
+
+ {l.say &&
{dict.whatToSay.replace("{text}", l.say)}
}
+
+
+
+ );
+ })}
+
+
+ {dict.total}
+ {money(total)}
+
+
+ setStrip(e.target.checked)} />{" "}
+ {dict.strip}
+
+
+ {strip ? dict.saved.replace("{amount}", money(saved)) : ""}
+
+
+
+ {dict.note}
+ >
+ );
+}
diff --git a/components/sections/fraud/FlagsChatTour.tsx b/components/sections/fraud/FlagsChatTour.tsx
new file mode 100644
index 0000000..2419dde
--- /dev/null
+++ b/components/sections/fraud/FlagsChatTour.tsx
@@ -0,0 +1,104 @@
+"use client";
+
+import { Fragment, useEffect, useState } from "react";
+import type { FraudPageDict } from "@/lib/i18n/dictionary";
+import { ScrollTour } from "../shared/ScrollTour";
+import { usePrefersReducedMotion } from "../shared/usePrefersReducedMotion";
+
+type Dict = FraudPageDict["flags"];
+
+// Each red flag plays out as a short chat on a phone while its card is
+// the active step.
+export function FlagsChatTour({ dict }: { dict: Dict }) {
+ const [step, setStep] = useState(-1);
+ const total = dict.items.length;
+ const fill = (s: string, n: number) =>
+ s.replace("{n}", String(n)).replace("{total}", String(total));
+
+ const cards = dict.items.map((f, i) => (
+
+ {fill(dict.tag, i + 1)}
+ {f.title}
+ {f.body}
+ {dict.whatToDo.replace("{text}", f.todo)}
+
+ ));
+
+ return (
+
+
+
+ D
+
+
+ {dict.dealer}
+ {step >= 0 ? dict.items[step].title : dict.floor}
+
+
+ = 0 ? fill(dict.counter, step + 1) : ""} />
+
+ }
+ />
+ );
+}
+
+// Remounted for each step, so its timers restart from the beginning.
+function Conversation({
+ dict,
+ step,
+ counter,
+}: {
+ dict: Dict;
+ step: number;
+ counter: string;
+}) {
+ const reduce = usePrefersReducedMotion();
+ // 0 dealer typing, 1 dealer said, 2 you typing, 3 you said, 4 flag chip
+ const [phase, setPhase] = useState(0);
+
+ useEffect(() => {
+ if (step < 0) return;
+ if (reduce) {
+ setPhase(4);
+ return;
+ }
+ const ts = [700, 1300, 2100, 2600].map((ms, k) =>
+ setTimeout(() => setPhase(k + 1), ms),
+ );
+ return () => ts.forEach(clearTimeout);
+ }, [step, reduce]);
+
+ if (step < 0) {
+ return (
+