@higinio/design-mcp 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -322,7 +322,7 @@ html, body { overflow-x: clip; }
322
322
  .input-icon .input { padding-left: 40px; }
323
323
 
324
324
  .textarea { min-height: 96px; padding: 12px 14px; resize: vertical; line-height: var(--leading-base); }
325
- .textarea-counter { font-size: var(--text-xs); color: var(--text-disabled); text-align: right; }
325
+ .textarea-counter { font-size: var(--text-xs); color: var(--text-muted); text-align: right; }
326
326
 
327
327
  .select-wrap { position: relative; }
328
328
  .select { appearance: none; padding-right: 38px; cursor: pointer; }
@@ -608,7 +608,7 @@ html, body { overflow-x: clip; }
608
608
  }
609
609
  .alert > svg { width: 20px; height: 20px; flex: none; margin-top: 1px; }
610
610
  .alert__title { font-weight: var(--weight-semibold); margin: 0 0 2px; }
611
- .alert__body { opacity: .92; margin: 0; }
611
+ .alert__body { margin: 0; }
612
612
  .alert__close {
613
613
  margin-left: auto; flex: none; display: grid; place-items: center;
614
614
  width: 36px; height: 36px; border: 0; border-radius: var(--radius-sm);
@@ -823,6 +823,32 @@ html, body { overflow-x: clip; }
823
823
  .stat__delta--up { color: var(--success-text); }
824
824
  .stat__delta--down { color: var(--danger-text); }
825
825
 
826
+ /* Chip de métrica (§10.22): rótulo y valor en una pastilla de una línea */
827
+ .metric-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
828
+ .metric-chip {
829
+ display: inline-flex; align-items: center; gap: var(--space-2);
830
+ padding: var(--space-1) var(--space-3);
831
+ border: var(--border-width) solid var(--border); border-radius: var(--radius-full);
832
+ background: var(--surface);
833
+ font-family: var(--font-body); font-size: var(--text-sm); line-height: 1.5;
834
+ color: var(--text-secondary); white-space: nowrap;
835
+ }
836
+ .metric-chip svg { width: 16px; height: 16px; flex: none; color: var(--text-muted); }
837
+ .metric-chip__value {
838
+ font-weight: var(--weight-semibold); color: var(--link);
839
+ font-variant-numeric: tabular-nums;
840
+ }
841
+ button.metric-chip {
842
+ min-height: var(--control-height-md); padding-inline: var(--space-4);
843
+ cursor: pointer; text-align: left;
844
+ transition: background-color var(--duration-fast) var(--ease-out),
845
+ border-color var(--duration-fast) var(--ease-out),
846
+ transform var(--duration-instant) var(--ease-out);
847
+ }
848
+ button.metric-chip:hover { background: var(--accent-soft); border-color: var(--accent); }
849
+ button.metric-chip:active { background: var(--accent-soft-strong); transform: scale(.98); }
850
+ button.metric-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
851
+
826
852
  .pagination { display: flex; align-items: center; gap: 4px; list-style: none; padding: 0; margin: 0; }
827
853
  .pagination__btn {
828
854
  display: inline-grid; place-items: center;
@@ -868,7 +894,7 @@ html, body { overflow-x: clip; }
868
894
  .sidebar__item {
869
895
  display: flex; align-items: center; gap: 10px;
870
896
  padding: 10px 12px; border-radius: var(--radius-md);
871
- font-size: var(--text-sm); font-weight: var(--weight-medium);
897
+ font-family: var(--font-body); font-size: var(--text-sm); font-weight: var(--weight-medium);
872
898
  color: var(--text-secondary); text-decoration: none; border: 0; background: transparent;
873
899
  cursor: pointer; text-align: left; width: 100%;
874
900
  transition: background-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out);
@@ -878,6 +904,68 @@ html, body { overflow-x: clip; }
878
904
  .sidebar__item.is-active { background: var(--accent-soft-strong); color: var(--link); }
879
905
  .sidebar__item.is-active svg { color: var(--accent); }
880
906
 
907
+ /* Grupos con rótulo dentro del sidebar */
908
+ .sidebar__group { display: flex; flex-direction: column; gap: 2px; }
909
+ .sidebar__group + .sidebar__group { margin-top: var(--space-4); }
910
+ .sidebar__group-label {
911
+ padding: 0 12px var(--space-1);
912
+ font-size: var(--text-xs); font-weight: var(--weight-semibold);
913
+ text-transform: uppercase; letter-spacing: var(--tracking-label);
914
+ color: var(--text-muted); white-space: nowrap;
915
+ }
916
+ .sidebar__label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
917
+
918
+ /* Sidebar contraíble (§10.24): expandido 260 px, riel de iconos de 64 px.
919
+ El ancho cambia sin transición; solo los rótulos se funden con opacity y transform. */
920
+ .sidebar--collapsible .sidebar__label {
921
+ transition: opacity var(--duration-fast) var(--ease-out),
922
+ transform var(--duration-fast) var(--ease-out);
923
+ }
924
+ .sidebar__toggle { margin-top: auto; }
925
+ .sidebar.is-collapsed { width: 64px; padding-inline: var(--space-3); }
926
+ .sidebar.is-collapsed .sidebar__item { position: relative; justify-content: center; padding-inline: 0; }
927
+ .sidebar.is-collapsed .sidebar__toggle svg { transform: rotate(180deg); }
928
+ .sidebar.is-collapsed .sidebar__group + .sidebar__group { margin-top: var(--space-2); }
929
+ /* En el riel, el rótulo de grupo es un separador de 1 px; su texto sigue en el árbol de accesibilidad */
930
+ .sidebar.is-collapsed .sidebar__group-label {
931
+ height: 1px; padding: 0; margin: 0 var(--space-2) var(--space-2);
932
+ overflow: hidden; color: transparent; background: var(--border);
933
+ }
934
+ /* Oculto a la vista pero accesible (patrón de .u-visually-hidden) */
935
+ .sidebar.is-collapsed .sidebar__label,
936
+ .sidebar.is-collapsed .sidebar__group:first-child > .sidebar__group-label {
937
+ position: absolute; width: 1px; height: 1px; margin: -1px;
938
+ clip-path: inset(50%); overflow: hidden; white-space: nowrap;
939
+ }
940
+ .sidebar.is-collapsed .sidebar__label {
941
+ border-radius: var(--radius-sm); background: var(--tooltip-bg); color: var(--tooltip-text);
942
+ font-size: var(--text-xs); line-height: 16px;
943
+ pointer-events: none; z-index: 70;
944
+ opacity: 0; transform: translateX(-4px);
945
+ }
946
+ /* Tooltip del riel: el propio rótulo aparece a la derecha del ítem, también con teclado */
947
+ .sidebar.is-collapsed .sidebar__item:focus-visible .sidebar__label {
948
+ left: calc(100% + 8px); top: calc(50% - 14px); width: auto; height: auto;
949
+ margin: 0; padding: 6px 10px; clip-path: none; overflow: visible;
950
+ opacity: 1; transform: none; transition-delay: 400ms;
951
+ }
952
+ /* Por hover solo con puntero real — en touch quedaría pegado tras el tap */
953
+ @media (hover: hover) and (pointer: fine) {
954
+ .sidebar.is-collapsed .sidebar__item:hover .sidebar__label {
955
+ left: calc(100% + 8px); top: calc(50% - 14px); width: auto; height: auto;
956
+ margin: 0; padding: 6px 10px; clip-path: none; overflow: visible;
957
+ opacity: 1; transform: none; transition-delay: 400ms;
958
+ }
959
+ }
960
+ /* Por debajo de 768 px la navegación vive en un Drawer --left (§10.29), que abre el botón ☰
961
+ .sidebar-trigger (combinado con .icon-btn); desde 768 px el sidebar es fijo y el botón sobra */
962
+ @media (max-width: 767px) {
963
+ .sidebar--collapsible { display: none; }
964
+ }
965
+ @media (min-width: 768px) {
966
+ .sidebar-trigger { display: none; }
967
+ }
968
+
881
969
  .tabs { display: flex; gap: var(--space-6); border-bottom: var(--border-width) solid var(--border); }
882
970
  .tabs__tab {
883
971
  padding: 12px 4px; margin-bottom: -1px;
@@ -1082,6 +1170,7 @@ html, body { overflow-x: clip; }
1082
1170
  .calendar__weekdays,
1083
1171
  .calendar__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
1084
1172
  .calendar__weekdays { margin-bottom: 4px; }
1173
+ .calendar__week { display: contents; }
1085
1174
  .calendar__weekday {
1086
1175
  display: flex; align-items: center; justify-content: center; height: 28px;
1087
1176
  font-size: var(--text-xs); font-weight: var(--weight-medium); color: var(--text-muted);
@@ -1096,7 +1185,7 @@ html, body { overflow-x: clip; }
1096
1185
  color var(--duration-fast) var(--ease-out);
1097
1186
  }
1098
1187
  .calendar__day:hover:not(:disabled):not(.calendar__day--selected) { background: var(--accent-soft); }
1099
- .calendar__day--outside { color: var(--text-disabled); }
1188
+ .calendar__day--outside { color: var(--text-muted); }
1100
1189
  .calendar__day--today { font-weight: var(--weight-semibold); box-shadow: inset 0 0 0 1px var(--border-strong); }
1101
1190
  .calendar__day--selected { background: var(--accent); color: var(--text-on-primary); font-weight: var(--weight-semibold); }
1102
1191
  .calendar__day:disabled { color: var(--text-disabled); cursor: not-allowed; }
@@ -1287,6 +1376,14 @@ html, body { overflow-x: clip; }
1287
1376
  .ds-demo--grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); align-items: stretch; }
1288
1377
  .ds-demo:has(table) { overflow-x: auto; }
1289
1378
 
1379
+ /* Demo del sidebar contraíble: rejilla auto 1fr, el contenido sigue al riel sin animar el ancho */
1380
+ .ds-app-demo { display: grid; grid-template-columns: auto 1fr; align-items: stretch; gap: 0; min-height: 400px; padding: 0; }
1381
+ .ds-app-demo > .sidebar { border-radius: var(--radius-lg) 0 0 var(--radius-lg); }
1382
+ .ds-app-demo__main { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-3); min-width: 0; padding: var(--space-6); }
1383
+ @media (max-width: 767px) {
1384
+ .ds-app-demo { grid-template-columns: 1fr; min-height: 0; }
1385
+ }
1386
+
1290
1387
  .ds-code { margin: var(--space-2) 0 0; }
1291
1388
  .ds-code summary {
1292
1389
  cursor: pointer; user-select: none; font-size: var(--text-sm);
@@ -1824,7 +1921,7 @@ html, body { overflow-x: clip; }
1824
1921
  <svg>…icono 18px…</svg>
1825
1922
  </button>
1826
1923
  <!-- Variantes: --ghost (default) · --secondary · --primary
1827
- Tamaños: --sm 32px · (md 40px) · --lg 48px --&gt;</code></pre>
1924
+ Tamaños: --sm 36px · (md 44px) · --lg 48px --&gt;</code></pre>
1828
1925
  </div>
1829
1926
  </details>
1830
1927
  </div>
@@ -2297,11 +2394,11 @@ html, body { overflow-x: clip; }
2297
2394
  <div class="ds-demo ds-demo--col" style="max-width:420px">
2298
2395
  <div>
2299
2396
  <div class="progress-row"><span class="progress-label">Almacenamiento</span><span class="progress-value js-progress-value">68%</span></div>
2300
- <div class="progress"><div class="progress__bar js-progress-bar" style="width:68%" role="progressbar" aria-valuenow="68" aria-valuemin="0" aria-valuemax="100"></div></div>
2397
+ <div class="progress"><div class="progress__bar js-progress-bar" style="width:68%" role="progressbar" aria-label="Almacenamiento" aria-valuenow="68" aria-valuemin="0" aria-valuemax="100"></div></div>
2301
2398
  </div>
2302
2399
  <div>
2303
2400
  <div class="progress-row"><span class="progress-label">Tareas completadas</span><span class="progress-value">24/30</span></div>
2304
- <div class="progress"><div class="progress__bar progress__bar--success" style="width:80%" role="progressbar" aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div></div>
2401
+ <div class="progress"><div class="progress__bar progress__bar--success" style="width:80%" role="progressbar" aria-label="Tareas completadas" aria-valuenow="80" aria-valuemin="0" aria-valuemax="100"></div></div>
2305
2402
  </div>
2306
2403
  <div style="display:flex;align-items:center;gap:24px">
2307
2404
  <div class="progress-ring js-ring" data-value="68">
@@ -2516,6 +2613,30 @@ html, body { overflow-x: clip; }
2516
2613
  &lt;!-- Delta: --up (success-text) · --down (danger-text) · neutro (text-muted) --&gt;</code></pre>
2517
2614
  </div>
2518
2615
  </details>
2616
+
2617
+ <h4 style="margin-top:var(--space-10)">Chip de métrica</h4>
2618
+ <p class="ds-spec">Pastilla de una línea con rótulo y valor en <span class="u-mono">--link</span> · fila con <span class="u-mono">gap</span> que salta de línea en móvil · el chip interactivo es un <span class="u-mono">&lt;button&gt;</span> de 44 px con nombre accesible completo.</p>
2619
+ <div class="ds-demo">
2620
+ <div class="metric-chips">
2621
+ <span class="metric-chip"><span class="metric-chip__label">Pasos</span> <span class="metric-chip__value">6,240</span></span>
2622
+ <span class="metric-chip"><span class="metric-chip__label">Sueño</span> <span class="metric-chip__value">7 h 20 min</span></span>
2623
+ <button class="metric-chip" type="button" id="dsWaterChip" aria-label="Agua: 3 de 8 vasos. Sumar un vaso"><svg aria-hidden="true"><use href="#i-plus"/></svg><span class="metric-chip__label">Agua</span> <span class="metric-chip__value">3 de 8</span></button>
2624
+ </div>
2625
+ </div>
2626
+ <details class="ds-code"><summary>Ver código</summary>
2627
+ <div class="ds-code-box"><button class="ds-copy">Copiar</button>
2628
+ <pre class="ds-pre"><code>&lt;div class="metric-chips"&gt;
2629
+ &lt;span class="metric-chip"&gt;
2630
+ &lt;span class="metric-chip__label"&gt;Pasos&lt;/span&gt; &lt;span class="metric-chip__value"&gt;6,240&lt;/span&gt;
2631
+ &lt;/span&gt;
2632
+ &lt;button class="metric-chip" type="button" aria-label="Agua: 3 de 8 vasos. Sumar un vaso"&gt;
2633
+ &lt;svg aria-hidden="true"&gt;…plus…&lt;/svg&gt;
2634
+ &lt;span class="metric-chip__label"&gt;Agua&lt;/span&gt; &lt;span class="metric-chip__value"&gt;3 de 8&lt;/span&gt;
2635
+ &lt;/button&gt;
2636
+ &lt;/div&gt;
2637
+ &lt;!-- El aria-label se actualiza con el valor; empieza por el texto visible --&gt;</code></pre>
2638
+ </div>
2639
+ </details>
2519
2640
  </div>
2520
2641
 
2521
2642
  <!-- Pagination -->
@@ -2603,6 +2724,51 @@ html, body { overflow-x: clip; }
2603
2724
  &lt;/nav&gt;</code></pre>
2604
2725
  </div>
2605
2726
  </details>
2727
+
2728
+ <h4 style="margin-top:var(--space-10)">Sidebar contraíble</h4>
2729
+ <p class="ds-spec">Expandido 260 px · riel de iconos de 64 px con grupos separados por una línea · en el riel, el nombre aparece como tooltip al pasar el cursor o al enfocar con teclado · el ancho cambia sin transición y solo los rótulos se funden · por debajo de 768 px lo sustituye un Drawer <span class="u-mono">--left</span>.</p>
2730
+ <div class="ds-demo ds-app-demo">
2731
+ <nav class="sidebar sidebar--collapsible" id="demoAppNav" aria-label="Navegación de ejemplo">
2732
+ <div class="sidebar__group" role="group" aria-labelledby="demoAppNavG1">
2733
+ <span class="sidebar__group-label" id="demoAppNavG1">Trabajo</span>
2734
+ <a class="sidebar__item is-active" href="#comp-navegacion" aria-current="page"><svg aria-hidden="true"><use href="#i-home"/></svg><span class="sidebar__label">Inicio</span></a>
2735
+ <a class="sidebar__item" href="#comp-navegacion"><svg aria-hidden="true"><use href="#i-folder"/></svg><span class="sidebar__label">Proyectos</span></a>
2736
+ <a class="sidebar__item" href="#comp-navegacion"><svg aria-hidden="true"><use href="#i-calendar"/></svg><span class="sidebar__label">Calendario</span></a>
2737
+ </div>
2738
+ <div class="sidebar__group" role="group" aria-labelledby="demoAppNavG2">
2739
+ <span class="sidebar__group-label" id="demoAppNavG2">Equipo</span>
2740
+ <a class="sidebar__item" href="#comp-navegacion"><svg aria-hidden="true"><use href="#i-chart"/></svg><span class="sidebar__label">Informes</span></a>
2741
+ <a class="sidebar__item" href="#comp-navegacion"><svg aria-hidden="true"><use href="#i-user"/></svg><span class="sidebar__label">Personas</span></a>
2742
+ <a class="sidebar__item" href="#comp-navegacion"><svg aria-hidden="true"><use href="#i-inbox"/></svg><span class="sidebar__label">Bandeja</span></a>
2743
+ </div>
2744
+ <button class="sidebar__item sidebar__toggle" type="button" aria-expanded="true" aria-controls="demoAppNav"><svg aria-hidden="true"><use href="#i-chevron-left"/></svg><span class="sidebar__label">Contraer</span></button>
2745
+ </nav>
2746
+ <div class="ds-app-demo__main">
2747
+ <button class="icon-btn icon-btn--secondary sidebar-trigger" type="button" data-drawer-open="demoNavDrawer" aria-label="Abrir navegación" aria-expanded="false" aria-controls="demoNavDrawer"><svg aria-hidden="true"><use href="#i-menu"/></svg></button>
2748
+ <h5 style="margin:0">Inicio</h5>
2749
+ <p class="ds-spec" style="margin:0">El contenido ocupa el ancho que deja el sidebar: la rejilla <span class="u-mono">auto 1fr</span> sigue al riel al instante, sin animar el ancho.</p>
2750
+ </div>
2751
+ </div>
2752
+ <details class="ds-code"><summary>Ver código</summary>
2753
+ <div class="ds-code-box"><button class="ds-copy">Copiar</button>
2754
+ <pre class="ds-pre"><code>&lt;nav class="sidebar sidebar--collapsible" id="appNav" aria-label="Principal"&gt;
2755
+ &lt;div class="sidebar__group" role="group" aria-labelledby="navTrabajo"&gt;
2756
+ &lt;span class="sidebar__group-label" id="navTrabajo"&gt;Trabajo&lt;/span&gt;
2757
+ &lt;a class="sidebar__item is-active" href="/" aria-current="page"&gt;
2758
+ &lt;svg aria-hidden="true"&gt;…&lt;/svg&gt;&lt;span class="sidebar__label"&gt;Inicio&lt;/span&gt;
2759
+ &lt;/a&gt;
2760
+ &lt;/div&gt;
2761
+ &lt;button class="sidebar__item sidebar__toggle" type="button"
2762
+ aria-expanded="true" aria-controls="appNav"&gt;
2763
+ &lt;svg aria-hidden="true"&gt;…chevron-left…&lt;/svg&gt;&lt;span class="sidebar__label"&gt;Contraer&lt;/span&gt;
2764
+ &lt;/button&gt;
2765
+ &lt;/nav&gt;
2766
+ &lt;!-- Contraído: .is-collapsed en el nav, aria-expanded="false" y texto «Expandir».
2767
+ Por debajo de 768 px: botón ☰ .sidebar-trigger que abre un .drawer.drawer--left con los mismos ítems. --&gt;
2768
+ &lt;button class="icon-btn sidebar-trigger" type="button" aria-label="Abrir navegación"
2769
+ aria-expanded="false" aria-controls="navDrawer"&gt;…menu…&lt;/button&gt;</code></pre>
2770
+ </div>
2771
+ </details>
2606
2772
  </div>
2607
2773
 
2608
2774
  <!-- Skeleton y EmptyState -->
@@ -2804,7 +2970,7 @@ html, body { overflow-x: clip; }
2804
2970
  <label class="field__label" for="dpInput">Fecha de entrega</label>
2805
2971
  <div class="datepicker" id="demoDatepicker">
2806
2972
  <input class="datepicker__input" id="dpInput" type="text" readonly autocomplete="off"
2807
- aria-haspopup="dialog" aria-expanded="false" aria-controls="dpCal" placeholder="Elige una fecha">
2973
+ aria-haspopup="dialog" aria-controls="dpCal" placeholder="Elige una fecha">
2808
2974
  <svg class="datepicker__icon" aria-hidden="true"><use href="#i-calendar"/></svg>
2809
2975
  <div class="datepicker__calendar" id="dpCal" role="dialog" aria-label="Elegir fecha" tabindex="-1">
2810
2976
  <div class="calendar">
@@ -2813,6 +2979,7 @@ html, body { overflow-x: clip; }
2813
2979
  <span class="calendar__title" aria-live="polite">—</span>
2814
2980
  <button class="icon-btn icon-btn--ghost icon-btn--sm" type="button" data-cal-next aria-label="Mes siguiente"><svg><use href="#i-chevron-right"/></svg></button>
2815
2981
  </div>
2982
+ <div class="calendar__table" role="grid" aria-label="Calendario">
2816
2983
  <div class="calendar__weekdays" role="row">
2817
2984
  <span class="calendar__weekday" role="columnheader" aria-label="lunes">lu</span>
2818
2985
  <span class="calendar__weekday" role="columnheader" aria-label="martes">ma</span>
@@ -2822,7 +2989,8 @@ html, body { overflow-x: clip; }
2822
2989
  <span class="calendar__weekday" role="columnheader" aria-label="sábado">sá</span>
2823
2990
  <span class="calendar__weekday" role="columnheader" aria-label="domingo">do</span>
2824
2991
  </div>
2825
- <div class="calendar__grid" id="dpGrid" role="grid" aria-label="Calendario"></div>
2992
+ <div class="calendar__grid" id="dpGrid" role="rowgroup"></div>
2993
+ </div>
2826
2994
  </div>
2827
2995
  </div>
2828
2996
  </div>
@@ -2832,7 +3000,7 @@ html, body { overflow-x: clip; }
2832
3000
  <div class="ds-code-box"><button class="ds-copy">Copiar</button>
2833
3001
  <pre class="ds-pre"><code>&lt;div class="datepicker"&gt;
2834
3002
  &lt;input class="datepicker__input" type="text" readonly
2835
- aria-haspopup="dialog" aria-expanded="false" aria-controls="cal"&gt;
3003
+ aria-haspopup="dialog" aria-controls="cal"&gt;
2836
3004
  &lt;svg class="datepicker__icon" aria-hidden="true"&gt;…calendario…&lt;/svg&gt;
2837
3005
  &lt;div class="datepicker__calendar" id="cal" role="dialog"
2838
3006
  aria-label="Elegir fecha" tabindex="-1"&gt;
@@ -2842,17 +3010,21 @@ html, body { overflow-x: clip; }
2842
3010
  &lt;span class="calendar__title"&gt;julio 2026&lt;/span&gt;
2843
3011
  &lt;button aria-label="Mes siguiente"&gt;…&lt;/button&gt;
2844
3012
  &lt;/div&gt;
3013
+ &lt;div class="calendar__table" role="grid" aria-label="julio 2026"&gt;
2845
3014
  &lt;div class="calendar__weekdays" role="row"&gt;
2846
3015
  &lt;span class="calendar__weekday" role="columnheader"
2847
3016
  aria-label="lunes"&gt;lu&lt;/span&gt; …
2848
3017
  &lt;/div&gt;
2849
- &lt;div class="calendar__grid" role="grid" aria-label="julio 2026"&gt;
3018
+ &lt;div class="calendar__grid" role="rowgroup"&gt;
3019
+ &lt;div class="calendar__week" role="row"&gt;
2850
3020
  &lt;button class="calendar__day calendar__day--today" role="gridcell"
2851
3021
  aria-label="viernes, 10 de julio de 2026"
2852
3022
  aria-selected="false"&gt;10&lt;/button&gt;
2853
3023
  &lt;button class="calendar__day calendar__day--selected" role="gridcell"
2854
3024
  aria-label="viernes, 17 de julio de 2026"
2855
3025
  aria-selected="true"&gt;17&lt;/button&gt; …
3026
+ &lt;/div&gt;
3027
+ &lt;/div&gt;
2856
3028
  &lt;/div&gt;
2857
3029
  &lt;/div&gt;
2858
3030
  &lt;/div&gt;
@@ -3221,7 +3393,7 @@ html, body { overflow-x: clip; }
3221
3393
  <p class="ds-lead">El sistema se distribuye como paquete npm (<span class="u-mono">@higinio/design-css</span>) y también como archivos sueltos en <span class="u-mono">dist/celeste-clasica/</span>. Instálalo o cópialos, y elige qué importar según tu stack (A/B/C). En todas: <strong>light por defecto</strong>; <span class="u-mono">&lt;html data-theme="dark"&gt;</span> activa el modo oscuro, y los componentes consumen <strong>solo aliases semánticos</strong>, nunca hex.</p>
3222
3394
 
3223
3395
  <h3>Instalar desde npm (recomendado)</h3>
3224
- <p>Un solo paquete con los dos sistemas en subrutas <span class="u-mono">/celeste/</span> y <span class="u-mono">/nocturna/</span>. Instálalo y usa las vías A/B/C apuntando a la subruta, en vez de a un archivo copiado.</p>
3396
+ <p>Un solo paquete con todos los sistemas, cada uno en su subruta; Celeste Clásica vive en <span class="u-mono">/celeste/</span>. Instálalo y usa las vías A/B/C apuntando a la subruta, en vez de a un archivo copiado.</p>
3225
3397
  <div class="ds-code-box"><button class="ds-copy">Copiar</button>
3226
3398
  <pre class="ds-pre"><code>npm i @higinio/design-css
3227
3399
 
@@ -3283,20 +3455,23 @@ npm i tailwindcss @tailwindcss/postcss
3283
3455
  <section id="mcp">
3284
3456
  <p class="ds-eyebrow">Sistema</p>
3285
3457
  <h2>MCP</h2>
3286
- <p class="ds-lead">El paquete <span class="code">@higinio/design-mcp</span> expone ambos sistemas de diseño — Celeste Clásica y Nocturna Eléctrica — a cualquier IDE o cliente compatible con Model Context Protocol: tokens, componentes, reglas duras y validación de código. Complementa a las skills de Claude, no las reemplaza: misma fuente de verdad, accesible también fuera del entorno de Claude.</p>
3458
+ <p class="ds-lead">El paquete <span class="code">@higinio/design-mcp</span> expone los sistemas de diseño de Higinio Sosa, entre ellos Celeste Clásica (<span class="u-mono">system="celeste"</span>), a cualquier IDE o cliente compatible con Model Context Protocol: tokens, componentes, reglas duras y validación de código. Complementa a las skills de Claude, no las reemplaza: misma fuente de verdad, accesible también fuera del entorno de Claude.</p>
3287
3459
 
3288
- <h3>Las 8 tools</h3>
3460
+ <h3>Las 11 tools</h3>
3289
3461
  <div class="ds-demo ds-demo--col" style="padding:0;overflow-x:auto">
3290
3462
  <table class="table">
3291
3463
  <thead><tr><th>Tool</th><th>Qué hace</th></tr></thead>
3292
3464
  <tbody>
3293
3465
  <tr><td class="u-mono">list_design_systems</td><td>Lista los sistemas de diseño disponibles.</td></tr>
3294
- <tr><td class="u-mono">get_token</td><td>Devuelve el valor resuelto de un token o alias de un sistema.</td></tr>
3466
+ <tr><td class="u-mono">get_token</td><td>Resuelve un alias semántico o un token DTCG por path a su valor.</td></tr>
3295
3467
  <tr><td class="u-mono">search_tokens</td><td>Busca tokens por nombre, categoría o valor.</td></tr>
3296
3468
  <tr><td class="u-mono">list_components</td><td>Lista los componentes documentados de un sistema.</td></tr>
3297
3469
  <tr><td class="u-mono">get_component_spec</td><td>Devuelve la especificación completa de un componente: estados, medidas, variantes.</td></tr>
3298
3470
  <tr><td class="u-mono">get_rules</td><td>Devuelve las reglas duras (no negociables) del sistema.</td></tr>
3299
3471
  <tr><td class="u-mono">validate_code</td><td>Audita CSS/HTML contra las reglas del sistema — hex directos, contraste, aliases.</td></tr>
3472
+ <tr><td class="u-mono">validate_motion</td><td>Audita el motion contra las reglas del sistema: <span class="u-mono">transition</span> sobre todas las propiedades, ease-in en entradas, propiedades de layout, duraciones por encima de <span class="u-mono">--duration-page</span>.</td></tr>
3473
+ <tr><td class="u-mono">check_slop</td><td>Detecta clichés de diseño generado por IA: gradientes, glassmorphism, sombras de negro puro, fuentes genéricas y copy de marketing.</td></tr>
3474
+ <tr><td class="u-mono">checklist_preflight</td><td>Checklist estático de pre-producción sobre HTML/CSS: metadatos, headings, imágenes y accesibilidad de controles.</td></tr>
3300
3475
  <tr><td class="u-mono">generate_snippet</td><td>Genera un snippet de componente listo para usar, con los aliases correctos.</td></tr>
3301
3476
  </tbody>
3302
3477
  </table>
@@ -3390,6 +3565,31 @@ npm i tailwindcss @tailwindcss/postcss
3390
3565
  </div>
3391
3566
  </div>
3392
3567
 
3568
+ <!-- Navegación móvil del Sidebar contraíble (§10.24): Drawer --left -->
3569
+ <div class="drawer drawer--left" id="demoNavDrawer" role="dialog" aria-modal="true" aria-labelledby="demoNavDrawerTitle">
3570
+ <div class="drawer__overlay" data-drawer-close></div>
3571
+ <div class="drawer__panel" tabindex="-1">
3572
+ <div class="drawer__header">
3573
+ <h4 class="drawer__title" id="demoNavDrawerTitle">Navegación</h4>
3574
+ <button class="icon-btn icon-btn--ghost" data-drawer-close aria-label="Cerrar"><svg><use href="#i-x"/></svg></button>
3575
+ </div>
3576
+ <nav class="drawer__body" aria-label="Navegación de ejemplo">
3577
+ <div class="sidebar__group" role="group" aria-labelledby="demoNavDrawerG1">
3578
+ <span class="sidebar__group-label" id="demoNavDrawerG1">Trabajo</span>
3579
+ <a class="sidebar__item is-active" href="#comp-navegacion" aria-current="page" data-drawer-close><svg aria-hidden="true"><use href="#i-home"/></svg><span class="sidebar__label">Inicio</span></a>
3580
+ <a class="sidebar__item" href="#comp-navegacion" data-drawer-close><svg aria-hidden="true"><use href="#i-folder"/></svg><span class="sidebar__label">Proyectos</span></a>
3581
+ <a class="sidebar__item" href="#comp-navegacion" data-drawer-close><svg aria-hidden="true"><use href="#i-calendar"/></svg><span class="sidebar__label">Calendario</span></a>
3582
+ </div>
3583
+ <div class="sidebar__group" role="group" aria-labelledby="demoNavDrawerG2">
3584
+ <span class="sidebar__group-label" id="demoNavDrawerG2">Equipo</span>
3585
+ <a class="sidebar__item" href="#comp-navegacion" data-drawer-close><svg aria-hidden="true"><use href="#i-chart"/></svg><span class="sidebar__label">Informes</span></a>
3586
+ <a class="sidebar__item" href="#comp-navegacion" data-drawer-close><svg aria-hidden="true"><use href="#i-user"/></svg><span class="sidebar__label">Personas</span></a>
3587
+ <a class="sidebar__item" href="#comp-navegacion" data-drawer-close><svg aria-hidden="true"><use href="#i-inbox"/></svg><span class="sidebar__label">Bandeja</span></a>
3588
+ </div>
3589
+ </nav>
3590
+ </div>
3591
+ </div>
3592
+
3393
3593
  <!-- Drawer de demostración (§10.29) -->
3394
3594
  <div class="drawer drawer--right" id="demoDrawer" role="dialog" aria-modal="true" aria-labelledby="demoDrawerTitle">
3395
3595
  <div class="drawer__overlay" data-drawer-close></div>
@@ -3843,6 +4043,31 @@ npm i tailwindcss @tailwindcss/postcss
3843
4043
  });
3844
4044
  });
3845
4045
 
4046
+ /* ---------- Sidebar contraíble (§10.24): riel de iconos ---------- */
4047
+ Array.prototype.forEach.call(d.querySelectorAll(".sidebar__toggle"), function (btn) {
4048
+ var nav = d.getElementById(btn.getAttribute("aria-controls"));
4049
+ var label = btn.querySelector(".sidebar__label");
4050
+ if (!nav) return;
4051
+ btn.addEventListener("click", function () {
4052
+ var collapsed = nav.classList.toggle("is-collapsed");
4053
+ btn.setAttribute("aria-expanded", collapsed ? "false" : "true");
4054
+ if (label) label.textContent = collapsed ? "Expandir" : "Contraer";
4055
+ });
4056
+ });
4057
+
4058
+ /* ---------- Chip de métrica (§10.22): sumar un vaso ---------- */
4059
+ var waterChip = d.getElementById("dsWaterChip");
4060
+ if (waterChip) {
4061
+ var waterValue = waterChip.querySelector(".metric-chip__value");
4062
+ var waterMax = 8, water = 3;
4063
+ waterChip.addEventListener("click", function () {
4064
+ water = water >= waterMax ? 0 : water + 1;
4065
+ waterValue.textContent = water + " de " + waterMax;
4066
+ waterChip.setAttribute("aria-label", "Agua: " + water + " de " + waterMax + " vasos. " +
4067
+ (water < waterMax ? "Sumar un vaso" : "Empezar de nuevo"));
4068
+ });
4069
+ }
4070
+
3846
4071
  /* ---------- Toast ---------- */
3847
4072
  var TOAST_DATA = {
3848
4073
  success: ["i-circle-check", "Cambios guardados", "El proyecto se actualizó correctamente."],
@@ -3988,6 +4213,7 @@ npm i tailwindcss @tailwindcss/postcss
3988
4213
  if (!dr) return;
3989
4214
  drawerTrigger = trigger || d.activeElement;
3990
4215
  dr.classList.add("is-open");
4216
+ if (drawerTrigger.hasAttribute("aria-expanded")) drawerTrigger.setAttribute("aria-expanded", "true");
3991
4217
  var f = modalFocusables(dr);
3992
4218
  var panel = dr.querySelector(".drawer__panel");
3993
4219
  window.setTimeout(function () { (f[0] || panel).focus(); }, 0);
@@ -3995,6 +4221,7 @@ npm i tailwindcss @tailwindcss/postcss
3995
4221
  function closeDrawer(dr) {
3996
4222
  if (!dr || !dr.classList.contains("is-open")) return;
3997
4223
  dr.classList.remove("is-open");
4224
+ if (drawerTrigger && drawerTrigger.hasAttribute("aria-expanded")) drawerTrigger.setAttribute("aria-expanded", "false");
3998
4225
  if (drawerTrigger && typeof drawerTrigger.focus === "function") drawerTrigger.focus();
3999
4226
  drawerTrigger = null;
4000
4227
  }
@@ -4152,6 +4379,7 @@ npm i tailwindcss @tailwindcss/postcss
4152
4379
  var dpInput = d.getElementById("dpInput");
4153
4380
  var dpCal = d.getElementById("dpCal");
4154
4381
  var dpGrid = d.getElementById("dpGrid");
4382
+ var dpTable = dpGrid.parentNode;
4155
4383
  var dpTitle = dp.querySelector(".calendar__title");
4156
4384
  var MONTHS = ["enero", "febrero", "marzo", "abril", "mayo", "junio",
4157
4385
  "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"];
@@ -4168,13 +4396,20 @@ npm i tailwindcss @tailwindcss/postcss
4168
4396
  function dpRender() {
4169
4397
  var y = view.getFullYear(), m = view.getMonth();
4170
4398
  dpTitle.textContent = MONTHS[m] + " " + y;
4171
- dpGrid.setAttribute("aria-label", MONTHS[m] + " " + y);
4399
+ dpTable.setAttribute("aria-label", MONTHS[m] + " " + y);
4172
4400
  dpGrid.innerHTML = "";
4173
4401
  var startDow = (new Date(y, m, 1).getDay() + 6) % 7; // lunes = 0
4174
4402
  var daysInMonth = new Date(y, m + 1, 0).getDate();
4175
4403
  var weeks = Math.ceil((startDow + daysInMonth) / 7);
4176
4404
  var start = new Date(y, m, 1 - startDow);
4405
+ var week = null;
4177
4406
  for (var i = 0; i < weeks * 7; i++) {
4407
+ if (i % 7 === 0) {
4408
+ week = d.createElement("div");
4409
+ week.className = "calendar__week";
4410
+ week.setAttribute("role", "row");
4411
+ dpGrid.appendChild(week);
4412
+ }
4178
4413
  var cell = new Date(start.getFullYear(), start.getMonth(), start.getDate() + i);
4179
4414
  var btn = d.createElement("button");
4180
4415
  btn.type = "button";
@@ -4189,7 +4424,7 @@ npm i tailwindcss @tailwindcss/postcss
4189
4424
  btn.setAttribute("aria-label", fmtLong.format(cell));
4190
4425
  btn.tabIndex = sameDay(cell, focusDate) ? 0 : -1;
4191
4426
  btn.setAttribute("data-ts", String(cell.getTime()));
4192
- dpGrid.appendChild(btn);
4427
+ week.appendChild(btn);
4193
4428
  }
4194
4429
  }
4195
4430
  function dpButtonFor(dt) { return dpGrid.querySelector('[data-ts="' + atMidnight(dt).getTime() + '"]'); }
@@ -4208,7 +4443,6 @@ npm i tailwindcss @tailwindcss/postcss
4208
4443
  }
4209
4444
  function dpOpen() {
4210
4445
  dp.classList.add("is-open");
4211
- dpInput.setAttribute("aria-expanded", "true");
4212
4446
  focusDate = new Date(selected);
4213
4447
  view = new Date(focusDate.getFullYear(), focusDate.getMonth(), 1);
4214
4448
  dpRender();
@@ -4217,7 +4451,6 @@ npm i tailwindcss @tailwindcss/postcss
4217
4451
  function dpClose(returnFocus) {
4218
4452
  if (!dp.classList.contains("is-open")) return;
4219
4453
  dp.classList.remove("is-open");
4220
- dpInput.setAttribute("aria-expanded", "false");
4221
4454
  if (returnFocus) dpInput.focus();
4222
4455
  }
4223
4456
  function dpSelect(dt) {