diff --git a/src/main/resources/static/css/acceso-denegado.css b/src/main/resources/static/css/acceso-denegado.css
new file mode 100644
index 0000000..8988fe9
--- /dev/null
+++ b/src/main/resources/static/css/acceso-denegado.css
@@ -0,0 +1,16 @@
+.denied-wrap {
+ display: flex; align-items: center; justify-content: center;
+ min-height: 100vh; padding: 2rem; text-align: center;
+}
+.denied-card {
+ background: var(--bg-alt); border: 1px solid var(--border);
+ border-radius: 12px; padding: 3rem 2rem; max-width: 480px; width: 100%;
+}
+.denied-card h2 { color: var(--error, #f44747); font-size: 1.5rem; margin-bottom: 1rem; }
+.denied-card p { color: var(--text-muted); margin-bottom: 1.5rem; line-height: 1.6; }
+.denied-card a {
+ display: inline-block; padding: .6rem 1.4rem; border-radius: 8px;
+ background: var(--accent); color: #fff; text-decoration: none;
+ font-weight: 600; transition: opacity .15s;
+}
+.denied-card a:hover { opacity: .88; }
diff --git a/src/main/resources/static/css/admin.css b/src/main/resources/static/css/admin.css
new file mode 100644
index 0000000..592bc00
--- /dev/null
+++ b/src/main/resources/static/css/admin.css
@@ -0,0 +1,73 @@
+body { padding-top: var(--topbar-h); }
+
+/* ── Topbar admin ── */
+.topbar { background: #1a1a2e; border-bottom-color: #3c3c6e; }
+.topbar-brand { color: #c792ea; }
+.admin-badge {
+ font-size: .72rem; font-weight: 700; padding: .15rem .5rem;
+ background: rgba(199,146,234,.15); color: #c792ea;
+ border: 1px solid #c792ea; border-radius: 4px;
+}
+
+/* ── Layout ── */
+.admin-wrap { max-width: 1100px; margin: 2rem auto; padding: 0 1.5rem; }
+.admin-wrap h1 { font-size: 1.4rem; color: var(--accent-2); margin-bottom: 1.5rem; }
+
+/* ── Mensajes ── */
+.msg-error {
+ padding: .6rem .9rem; border-radius: 6px; margin-bottom: 1rem;
+ background: rgba(244,71,71,.12); color: var(--error);
+ border: 1px solid var(--error); font-size: .88rem;
+}
+
+/* ── Nuevo usuario ── */
+.nuevo-form {
+ background: var(--bg-alt); border: 1px solid var(--border);
+ border-radius: 10px; padding: 1.2rem 1.4rem; margin-bottom: 2rem;
+ display: flex; flex-wrap: wrap; gap: .8rem; align-items: flex-end;
+}
+.nuevo-form h3 { width: 100%; font-size: 1rem; color: var(--accent-2); margin-bottom: .2rem; }
+.nuevo-form input[type="email"],
+.nuevo-form input[type="password"] {
+ background: var(--bg); border: 1px solid var(--border); border-radius: 6px;
+ color: var(--text); padding: .45rem .7rem; font-size: .9rem; min-width: 200px;
+}
+.nuevo-form label.check-label { display: flex; align-items: center; gap: .4rem;
+ font-size: .88rem; color: var(--text-muted); cursor: pointer; }
+.nuevo-btn {
+ padding: .45rem 1.1rem; border-radius: 6px; border: none;
+ background: var(--accent); color: #fff; font-weight: 600;
+ font-size: .9rem; cursor: pointer;
+}
+
+/* ── Tabla ── */
+.usuarios-table { width: 100%; border-collapse: collapse; font-size: .88rem; }
+.usuarios-table th {
+ background: var(--bg-alt); color: var(--text-muted); font-weight: 700;
+ text-transform: uppercase; font-size: .72rem; letter-spacing: .06em;
+ padding: .6rem .9rem; text-align: left; border-bottom: 1px solid var(--border);
+}
+.usuarios-table td {
+ padding: .6rem .9rem; border-bottom: 1px solid var(--border);
+ vertical-align: middle;
+}
+.usuarios-table tr:hover td { background: var(--bg-hover); }
+
+/* Badges de estado */
+.badge {
+ display: inline-block; font-size: .72rem; font-weight: 700;
+ padding: .15rem .5rem; border-radius: 4px;
+}
+.badge-on { background: rgba(106,153,85,.15); color: #6a9955; border: 1px solid #6a9955; }
+.badge-off { background: rgba(244,71,71,.1); color: var(--error); border: 1px solid var(--error); }
+.badge-admin { background: rgba(199,146,234,.15); color: #c792ea; border: 1px solid #c792ea; }
+
+/* Botones de acción */
+.btn-accion {
+ padding: .3rem .7rem; border-radius: 5px; border: 1px solid var(--border);
+ background: var(--bg); color: var(--text); font-size: .8rem;
+ cursor: pointer; transition: border-color .12s, color .12s;
+}
+.btn-accion:hover { border-color: var(--accent); color: var(--accent-2); }
+.btn-accion.danger:hover { border-color: var(--error); color: var(--error); }
+.acciones { display: flex; gap: .4rem; flex-wrap: wrap; }
diff --git a/src/main/resources/static/css/leyes.css b/src/main/resources/static/css/leyes.css
new file mode 100644
index 0000000..241c693
--- /dev/null
+++ b/src/main/resources/static/css/leyes.css
@@ -0,0 +1,174 @@
+.leyes-layout {
+ display: flex;
+ height: calc(100vh - var(--topbar-h));
+ margin-top: var(--topbar-h);
+ overflow: hidden;
+}
+
+/* ── Panel izquierdo ─── */
+.leyes-sidebar {
+ width: 320px;
+ flex-shrink: 0;
+ background: var(--bg-alt);
+ border-right: 1px solid var(--border);
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+}
+.leyes-sidebar-header {
+ padding: 1rem 1.1rem .8rem;
+ border-bottom: 1px solid var(--border);
+ flex-shrink: 0;
+}
+.leyes-sidebar-header h2 {
+ font-size: .9rem;
+ font-weight: 700;
+ color: var(--accent-2);
+ text-transform: uppercase;
+ letter-spacing: .06em;
+ margin-bottom: .5rem;
+}
+.leyes-search {
+ display: flex;
+ align-items: center;
+ background: var(--bg);
+ border: 1px solid var(--border);
+ border-radius: 6px;
+ padding: .35rem .7rem;
+ gap: .5rem;
+}
+.leyes-search i { color: var(--text-muted); font-size: .85rem; }
+.leyes-search input {
+ background: none;
+ border: none;
+ outline: none;
+ color: var(--text);
+ font-size: .85rem;
+ width: 100%;
+}
+.leyes-search input::placeholder { color: var(--text-muted); }
+
+.leyes-list {
+ overflow-y: auto;
+ flex: 1;
+ padding: .5rem 0;
+}
+
+.ley-grupo-label {
+ font-size: .7rem;
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: .07em;
+ color: var(--text-muted);
+ padding: .7rem 1.1rem .3rem;
+}
+.ley-item {
+ display: flex;
+ flex-direction: column;
+ gap: .2rem;
+ padding: .6rem 1.1rem;
+ cursor: pointer;
+ border-left: 3px solid transparent;
+ transition: background .12s, border-color .12s;
+}
+.ley-item:hover { background: var(--bg-hover); }
+.ley-item.active {
+ background: var(--bg-hover);
+ border-left-color: var(--accent);
+}
+.ley-item.hidden { display: none; }
+.ley-nombre {
+ font-size: .87rem;
+ font-weight: 600;
+ color: var(--text);
+ line-height: 1.3;
+}
+.ley-subtitulo {
+ font-size: .75rem;
+ color: var(--text-muted);
+}
+.ley-badge {
+ display: inline-block;
+ font-size: .68rem;
+ font-weight: 700;
+ padding: .1rem .4rem;
+ border-radius: 4px;
+ background: rgba(0,122,204,.15);
+ color: var(--accent);
+ margin-top: .1rem;
+ width: fit-content;
+}
+
+/* ── Panel derecho ─── */
+.leyes-viewer {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+}
+.leyes-viewer-header {
+ display: flex;
+ align-items: center;
+ gap: .8rem;
+ padding: .75rem 1.2rem;
+ background: var(--bg-alt);
+ border-bottom: 1px solid var(--border);
+ flex-shrink: 0;
+}
+.leyes-viewer-title {
+ font-size: .9rem;
+ font-weight: 600;
+ color: var(--text);
+ flex: 1;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.leyes-viewer-actions {
+ display: flex;
+ gap: .5rem;
+ flex-shrink: 0;
+}
+.leyes-btn {
+ display: inline-flex;
+ align-items: center;
+ gap: .4rem;
+ font-size: .8rem;
+ font-weight: 600;
+ padding: .35rem .8rem;
+ border-radius: 6px;
+ background: var(--bg);
+ border: 1px solid var(--border);
+ color: var(--text);
+ text-decoration: none;
+ cursor: pointer;
+ transition: background .12s, border-color .12s;
+}
+.leyes-btn:hover { background: var(--bg-hover); border-color: var(--accent); color: var(--accent-2); }
+.leyes-btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
+.leyes-btn.primary:hover { background: #0090e8; }
+
+.leyes-viewer iframe {
+ flex: 1;
+ border: none;
+ width: 100%;
+ height: 100%;
+}
+.leyes-placeholder {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 1rem;
+ color: var(--text-muted);
+}
+.leyes-placeholder i { font-size: 3rem; opacity: .3; }
+.leyes-placeholder p { font-size: .95rem; }
+
+/* ── Responsive ─── */
+@media (max-width: 700px) {
+ .leyes-layout { flex-direction: column; height: auto; overflow: auto; }
+ .leyes-sidebar { width: 100%; height: 260px; border-right: none; border-bottom: 1px solid var(--border); }
+ .leyes-viewer { height: calc(100vh - var(--topbar-h) - 260px); min-height: 400px; }
+}
diff --git a/src/main/resources/static/css/pagar.css b/src/main/resources/static/css/pagar.css
new file mode 100644
index 0000000..e7e2dc4
--- /dev/null
+++ b/src/main/resources/static/css/pagar.css
@@ -0,0 +1,33 @@
+.pagar-wrap {
+ display: flex; align-items: center; justify-content: center;
+ min-height: 100vh; padding: 5rem 1.5rem 2rem;
+}
+.pagar-card {
+ background: var(--bg-alt); border: 1px solid var(--border);
+ border-radius: 14px; padding: 2.5rem 2rem; width: 100%; max-width: 500px;
+}
+.pagar-card h2 { color: var(--accent-2); font-size: 1.4rem; margin-bottom: .4rem; }
+.pagar-precio {
+ font-size: 2.8rem; font-weight: 700; color: var(--accent);
+ margin: 1.2rem 0 .3rem;
+}
+.pagar-precio small { font-size: 1rem; color: var(--text-muted); font-weight: 400; }
+.pagar-features { list-style: none; padding: 0; margin: 1.2rem 0 1.8rem; }
+.pagar-features li { padding: .4rem 0; color: var(--text-muted); font-size: .9rem; }
+.pagar-features li i { color: var(--accent); margin-right: .5rem; width: 1rem; }
+.pagar-badge {
+ display: inline-block; font-size: .75rem; padding: .25rem .7rem;
+ border-radius: 20px; background: rgba(106,153,85,.15);
+ color: var(--success, #6a9955); border: 1px solid var(--success, #6a9955);
+ margin-bottom: 1rem;
+}
+.btn-stripe {
+ display: flex; align-items: center; justify-content: center; gap: .6rem;
+ width: 100%; padding: .8rem; border-radius: 10px; border: none;
+ background: #635BFF; color: #fff; font-size: 1rem;
+ font-weight: 700; cursor: pointer; font-family: inherit;
+ transition: opacity .15s;
+}
+.btn-stripe:hover { opacity: .88; }
+.pagar-footer { margin-top: 1rem; font-size: .78rem; color: var(--text-muted); text-align: center; }
+.pagar-footer a { color: var(--accent); }
diff --git a/src/main/resources/static/css/pago-cancelado.css b/src/main/resources/static/css/pago-cancelado.css
new file mode 100644
index 0000000..df6da75
--- /dev/null
+++ b/src/main/resources/static/css/pago-cancelado.css
@@ -0,0 +1,10 @@
+.result-wrap { display:flex; align-items:center; justify-content:center; min-height:100vh; padding:2rem; text-align:center; }
+.result-card { background:var(--bg-alt); border:1px solid var(--border); border-radius:14px; padding:3rem 2rem; max-width:460px; width:100%; }
+.result-icon { font-size:3rem; color:var(--text-muted); margin-bottom:1rem; }
+.result-card h2 { color:var(--accent-2); font-size:1.4rem; margin-bottom:.8rem; }
+.result-card p { color:var(--text-muted); line-height:1.6; margin-bottom:1.5rem; }
+.btn-row { display:flex; gap:1rem; justify-content:center; flex-wrap:wrap; }
+.btn-row a { display:inline-block; padding:.6rem 1.4rem; border-radius:8px; text-decoration:none; font-weight:700; transition:opacity .15s; }
+.btn-primary { background:var(--accent); color:#fff; }
+.btn-secondary { background:var(--bg-hover); color:var(--text); }
+.btn-row a:hover { opacity:.85; }
diff --git a/src/main/resources/static/css/pago-exito.css b/src/main/resources/static/css/pago-exito.css
new file mode 100644
index 0000000..2888200
--- /dev/null
+++ b/src/main/resources/static/css/pago-exito.css
@@ -0,0 +1,8 @@
+.result-wrap { display:flex; align-items:center; justify-content:center; min-height:100vh; padding:2rem; text-align:center; }
+.result-card { background:var(--bg-alt); border:1px solid var(--border); border-radius:14px; padding:3rem 2rem; max-width:460px; width:100%; }
+.result-icon { font-size:3rem; color:var(--success,#6a9955); margin-bottom:1rem; }
+.result-card h2 { color:var(--accent-2); font-size:1.4rem; margin-bottom:.8rem; }
+.result-card p { color:var(--text-muted); line-height:1.6; margin-bottom:1.5rem; }
+.result-card a { display:inline-block; padding:.65rem 1.6rem; border-radius:8px; background:var(--accent); color:#fff; text-decoration:none; font-weight:700; transition:opacity .15s; }
+.result-card a:hover { opacity:.85; }
+.result-note { margin-top:1rem; font-size:.8rem; color:var(--text-muted); }
diff --git a/src/main/resources/static/css/registro.css b/src/main/resources/static/css/registro.css
new file mode 100644
index 0000000..c2a3dbc
--- /dev/null
+++ b/src/main/resources/static/css/registro.css
@@ -0,0 +1,6 @@
+/* Overrides y estilos específicos de la página de registro */
+.auth-card { max-width: 420px; }
+.auth-card h2 { margin-bottom: .4rem; }
+.auth-card p.subtitle { color: var(--text-muted); font-size: .88rem; margin-bottom: 1.5rem; }
+.auth-msg.info { background: rgba(0,122,204,.08); color: var(--accent); border: 1px solid var(--accent); }
+.hint { font-size: .78rem; color: var(--text-muted); margin-top: .2rem; }
diff --git a/src/main/resources/static/js/curso.js b/src/main/resources/static/js/curso.js
index e049a6a..99d5809 100644
--- a/src/main/resources/static/js/curso.js
+++ b/src/main/resources/static/js/curso.js
@@ -134,7 +134,7 @@ function renderMarkdown(md, tema, bloque, bloqueId, temaNum) {
Leyes de este tema
${tema.leyes.map(l =>
- `
+ `
${l.label}
`
).join('')}
diff --git a/src/main/resources/static/leyes/01 Retribuciones personal funcionario 2023.pdf b/src/main/resources/static/leyes/01 Retribuciones personal funcionario 2023.pdf
new file mode 100644
index 0000000..dd7d2ad
Binary files /dev/null and b/src/main/resources/static/leyes/01 Retribuciones personal funcionario 2023.pdf differ
diff --git a/src/main/resources/static/leyes/1-6-Sociedad-de-la-informacion-BOE-A-2002-13758-consolidado.pdf b/src/main/resources/static/leyes/1-6-Sociedad-de-la-informacion-BOE-A-2002-13758-consolidado.pdf
new file mode 100644
index 0000000..b072173
Binary files /dev/null and b/src/main/resources/static/leyes/1-6-Sociedad-de-la-informacion-BOE-A-2002-13758-consolidado.pdf differ
diff --git a/src/main/resources/static/leyes/1-6-firma-electronica-BOE-A-2003-23399-consolidado.pdf b/src/main/resources/static/leyes/1-6-firma-electronica-BOE-A-2003-23399-consolidado.pdf
new file mode 100644
index 0000000..872f0bc
Binary files /dev/null and b/src/main/resources/static/leyes/1-6-firma-electronica-BOE-A-2003-23399-consolidado.pdf differ
diff --git a/src/main/resources/static/leyes/1-7-BOE-A-2018-16673-consolidado.pdf b/src/main/resources/static/leyes/1-7-BOE-A-2018-16673-consolidado.pdf
new file mode 100644
index 0000000..7cfbca5
Binary files /dev/null and b/src/main/resources/static/leyes/1-7-BOE-A-2018-16673-consolidado.pdf differ
diff --git a/src/main/resources/static/leyes/BOE-A-1978-31229-consolidado.pdf b/src/main/resources/static/leyes/BOE-A-1978-31229-consolidado.pdf
new file mode 100644
index 0000000..d1e0f5d
--- /dev/null
+++ b/src/main/resources/static/leyes/BOE-A-1978-31229-consolidado.pdf
@@ -0,0 +1,2198 @@
+%PDF-1.5
%
+2163 0 obj
+<>
+endobj
+
+2192 0 obj
+<<510FF3D769F778C01E523C06088022D1>]/Filter/FlateDecode/W[1 3 1]/Index[2163 530]/Size 2693/Prev 326013/Type/XRef>>stream
+xjjSs[5ҢjjfJ4jN$yOD"VnBlEl-l܀+ O7ś{6gueelI~_%Y%{~[o/9풷~X=Kwl[r%位Koɇ?/%]K~C+v.%_u+kV~z,F9QNrST9MN3dl3,9[Αs<9_."X6%r\&r\%W5r\'
I6QMr"6Mnr);d%w=Kr/ȃ쑇yT'IyJ<+r@^%yY^W5y]ސK
+w.܅p]w.܅p]w.܅p]w.܅p]w.܅p]w.܅p]w.܅p]w.܅p]w.܅p]w.܅p]w.܅p]w.܅p]wco.iͼ7f̛y3oͼ7f̛y3oͼ7f̛y3oͼ7f̛y3oͼ7f̛y3oͼ7f̛y3oͼ7f̛y3oͼ7f̛y3oͼ7f̛y3oͼ7f̛y3oͼ7f̛y3oͼ7f̛y3oͼ700000000000000000000000000000000000000000000000000a>̇0|a>̇0|a>̇0|a>̇0|a>̇0|a>̇0|a>̇0|a>̇0|a>̇0|a>̇0|a>̇0|a>̏/+ZY~M;Vw
+endstream
+endobj
+
+2692 0 obj
+<>
+stream
+xUJP=7$kjV8REKDh:
+NhqQO