/* ai·radar · "Bento Keynote" components and layout.
   Every value reads a token from tokens.css; the language behind them is docs/ngon-ngu-thiet-ke.md.
   Layout: one 12-column bento. The lead story takes 8×2, the rest of the first screen is 4- to 7-column tiles. */

/* Be Vietnam Pro, served from this site (fonts/, SIL OFL 1.1 in fonts/OFL.txt): the same unhinted woff2 subsets
   Google Fonts serves to phones and Macs, so the type is unchanged, without a render-blocking stylesheet from another
   host. Per weight the vietnamese face comes last: where ranges overlap the last face wins, so ă đ ơ ư never pull in
   latin-ext. */
@font-face{font-family:"Be Vietnam Pro";font-style:normal;font-weight:400;font-display:swap;src:url(fonts/be-vietnam-pro-400-latin-ext.woff2) format("woff2");unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"Be Vietnam Pro";font-style:normal;font-weight:400;font-display:swap;src:url(fonts/be-vietnam-pro-400-latin.woff2) format("woff2");unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"Be Vietnam Pro";font-style:normal;font-weight:400;font-display:swap;src:url(fonts/be-vietnam-pro-400-vietnamese.woff2) format("woff2");unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB}
@font-face{font-family:"Be Vietnam Pro";font-style:normal;font-weight:500;font-display:swap;src:url(fonts/be-vietnam-pro-500-latin-ext.woff2) format("woff2");unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"Be Vietnam Pro";font-style:normal;font-weight:500;font-display:swap;src:url(fonts/be-vietnam-pro-500-latin.woff2) format("woff2");unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"Be Vietnam Pro";font-style:normal;font-weight:500;font-display:swap;src:url(fonts/be-vietnam-pro-500-vietnamese.woff2) format("woff2");unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB}
@font-face{font-family:"Be Vietnam Pro";font-style:normal;font-weight:600;font-display:swap;src:url(fonts/be-vietnam-pro-600-latin-ext.woff2) format("woff2");unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"Be Vietnam Pro";font-style:normal;font-weight:600;font-display:swap;src:url(fonts/be-vietnam-pro-600-latin.woff2) format("woff2");unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"Be Vietnam Pro";font-style:normal;font-weight:600;font-display:swap;src:url(fonts/be-vietnam-pro-600-vietnamese.woff2) format("woff2");unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB}
@font-face{font-family:"Be Vietnam Pro";font-style:normal;font-weight:700;font-display:swap;src:url(fonts/be-vietnam-pro-700-latin-ext.woff2) format("woff2");unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"Be Vietnam Pro";font-style:normal;font-weight:700;font-display:swap;src:url(fonts/be-vietnam-pro-700-latin.woff2) format("woff2");unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"Be Vietnam Pro";font-style:normal;font-weight:700;font-display:swap;src:url(fonts/be-vietnam-pro-700-vietnamese.woff2) format("woff2");unicode-range:U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB}

@layer base, layout, components, motion;

@layer base{
  *,*::before,*::after{box-sizing:border-box}
  html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;scroll-padding-top:calc(var(--bar-h) + var(--space-16));overflow-x:clip}
  body{margin:0;background:var(--color-canvas);color:var(--color-ink);font-family:var(--family);font-size:var(--text-body);line-height:var(--leading-body);
    -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;overflow-x:clip}
  a{color:inherit;text-decoration:none}
  button{font:inherit;color:inherit;background:none;border:0;padding:0;margin:0;cursor:pointer;text-align:inherit}
  button:disabled{cursor:default}
  img{display:block;max-width:100%}
  h1,h2,h3,p,ol,ul,dl,dd{margin:0}
  ol,ul{padding:0;list-style:none}
  .num{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
  [hidden]{display:none !important}
  .sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  .i{width:18px;height:18px;flex:none;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
  :focus-visible{outline:var(--focus-ring);outline-offset:var(--focus-offset);border-radius:var(--radius-8)}
  .skip{position:fixed;left:var(--space-16);top:-80px;z-index:100;background:var(--color-ink);color:var(--color-surface);padding:var(--space-12) var(--space-16);border-radius:var(--radius-12)}
  .skip:focus{top:var(--space-16)}
  .faint,.muted{color:var(--color-ink-3)}
  .tiny{font-size:var(--text-micro)}
  kbd{font-family:var(--family);font-size:var(--text-micro);font-weight:var(--weight-semibold);padding:1px var(--space-8);border-radius:var(--radius-8);background:var(--color-fill);color:var(--color-ink)}
}

/* ---------------------------------------------------------------- layout */
@layer layout{
  .bar{position:sticky;top:0;z-index:30;height:var(--bar-h);display:flex;align-items:center;gap:var(--space-24);
    padding:0 max(var(--page-pad), calc((100vw - var(--page-max)) / 2));background:var(--color-canvas);transition:box-shadow var(--motion-state) var(--ease-flow)}
  .bar.scrolled{box-shadow:0 1px 0 var(--color-hair)}
  main{max-width:calc(var(--page-max) + var(--page-pad) * 2);margin:0 auto;padding:var(--space-16) var(--page-pad) var(--space-96)}

  .board{display:grid;grid-template-columns:repeat(12, minmax(0, 1fr));gap:var(--grid-gap);align-items:stretch}
  .board:focus{outline:none}
  .t-lead{grid-column:span 6}
  .t-live,.t-repo{grid-column:span 3}
  .t-hot{grid-column:span 7}
  .t-new{grid-column:span 5}
  .t-listen{grid-column:span 5}
  .t-model{grid-column:span 4}
  .t-src{grid-column:span 3}
  .t-empty{grid-column:1 / -1}

  .chapters{display:grid;grid-template-columns:repeat(2, minmax(0, 1fr));gap:var(--grid-gap);margin-top:var(--space-96)}
  .chap-title{grid-column:1 / -1;font-size:var(--text-lead);font-weight:var(--weight-bold);letter-spacing:var(--tracking-display);line-height:var(--leading-tight)}
  .ch.wide{grid-column:1 / -1}
  .foot{margin:var(--space-48) auto 0;max-width:72ch;text-align:center;font-size:var(--text-meta);color:var(--color-ink-3);text-wrap:pretty}
  .foot .btn-quiet{margin-top:var(--space-8)}

  @media (min-width: 1800px){ :root{ --page-max: 1640px; } }
  /* Desktop: the lead stands on the left across two rows. Beside it, live and repositories share the first row
     and "new" takes the full right-hand width under them, so no tile is stretched to the lead's height.
     The tiles after them flow into the rows below (hot 7 + listen 5, model 8 + source 4). */
  @media (min-width: 1280px){
    .t-lead{grid-column:1 / span 6;grid-row:1 / span 2}
    .t-live{grid-column:7 / span 3;grid-row:1}
    .t-repo{grid-column:10 / span 3;grid-row:1}
    .t-new{grid-column:7 / span 6;grid-row:2}
    .t-model{grid-column:span 8}
    .t-src{grid-column:span 4}
  }
  /* Laptop: the right column holds two tiles, so the 4-column tiles get one more column each. */
  @media (min-width: 1100px) and (max-width: 1279px){
    .t-lead{grid-column:1 / -1} .t-live,.t-repo{grid-column:span 6}
    .t-listen{grid-column:span 6} .t-model{grid-column:span 6} .t-src{grid-column:span 12}
  }
  /* Tablet: six columns, the lead on its own row. */
  @media (max-width: 1099px){
    .board{grid-template-columns:repeat(6, minmax(0, 1fr))}
    .t-lead{grid-column:1 / -1;grid-row:auto}
    .t-live,.t-repo,.t-new,.t-listen,.t-model,.t-src{grid-column:span 3}
    .t-hot{grid-column:1 / -1}
    .nav{display:none}
  }
  /* Phone: one column, a quick-jump tab bar at the bottom. */
  @media (max-width: 767px){
    .board,.chapters{grid-template-columns:minmax(0, 1fr)}
    .board > .tile{grid-column:1 / -1 !important}
    .chapters{margin-top:var(--space-48)}
    .bar{gap:var(--space-8)}
    .ed-link{padding:6px 10px}
    .tc-link{padding:6px 8px;width:32px;height:32px;justify-content:center}
    .tc-link .tc-label{display:none}
    .when-line,.src-state .w{display:none}
    main{padding-bottom:calc(var(--space-96) + 24px)}
  }
}

/* ---------------------------------------------------------------- components */
@layer components{
  /* bar */
  .brand{font-size:var(--text-tile);font-weight:var(--weight-bold);letter-spacing:var(--tracking-display);white-space:nowrap}
  .brand b{color:var(--color-accent)}
  /* Link to the daily edition page. Neutral like the "Bản tin" badge on that page: blue stays for action and the selected item. */
  .ed-link{position:relative;flex:none;padding:6px 12px;border-radius:var(--radius-full);background:var(--color-fill);color:var(--color-ink-2);font-size:var(--text-meta);font-weight:var(--weight-semibold);line-height:20px;white-space:nowrap;transition:color var(--motion-state) var(--ease-flow)}
  .ed-link::after{content:"";position:absolute;inset:-6px -4px}
  .ed-link:hover{color:var(--color-ink)}
  /* Link to story search page. Matches .ed-link idiom in the header bar. */
  .tc-link{position:relative;flex:none;display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border-radius:var(--radius-full);background:var(--color-fill);color:var(--color-ink-2);font-size:var(--text-meta);font-weight:var(--weight-semibold);line-height:20px;white-space:nowrap;transition:color var(--motion-state) var(--ease-flow), background-color var(--motion-state) var(--ease-flow)}
  .tc-link::after{content:"";position:absolute;inset:-6px -4px}
  .tc-link:hover{color:var(--color-ink);background:var(--color-hair)}
  .tc-link:focus-visible{border-radius:var(--radius-full)}
  .tc-link .i{width:14px;height:14px}
  .when-line{display:none;font-size:var(--text-meta);color:var(--color-ink-2);white-space:nowrap}
  .nav{display:flex;gap:var(--space-4);flex:1;min-width:0;overflow-x:auto;scrollbar-width:none;mask-image:var(--nav-fade);font-size:var(--text-meta);font-weight:var(--weight-medium)}
  .nav a{padding:var(--space-8) var(--space-8);border-radius:var(--radius-full);color:var(--color-ink-2);white-space:nowrap;transition:color var(--motion-state) var(--ease-flow), background-color var(--motion-state) var(--ease-flow)}
  .nav a:hover{color:var(--color-ink);background:var(--color-fill)}
  .nav a[aria-current="true"]{color:var(--color-ink);background:var(--color-surface)}
  .nav .n{color:var(--color-accent);font-weight:var(--weight-semibold)}
  .src-state{display:flex;align-items:center;gap:var(--space-8);margin-left:auto;font-size:var(--text-meta);color:var(--color-ink-2);white-space:nowrap;min-height:var(--btn-h)}
  .live-at{display:inline-flex;align-items:center;gap:var(--space-4);margin-left:var(--space-8)}
  .src-state .i{width:14px;height:14px}
  .dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--color-fill);flex:none}
  .dot.ok{background:var(--color-ok)} .dot.warn{background:var(--color-warn)}
  .theme{position:relative;width:var(--btn-h);height:var(--btn-h);display:grid;place-items:center;border-radius:var(--radius-full);color:var(--color-ink-2);flex:none;
    transition:background-color var(--motion-state) var(--ease-flow), color var(--motion-state) var(--ease-flow), transform var(--motion-feedback) var(--ease-press)}
  .theme:hover{background:var(--color-fill);color:var(--color-ink)}
  .theme:active{transform:scale(0.92)}
  .theme .i{grid-area:1/1;transition:opacity var(--motion-state) var(--ease-flow), transform var(--motion-count) var(--ease-flow)}
  .theme .i-moon{opacity:0;transform:rotate(-60deg) scale(0.6)}
  .theme[aria-pressed="true"] .i-sun{opacity:0;transform:rotate(60deg) scale(0.6)}
  .theme[aria-pressed="true"] .i-moon{opacity:1;transform:none}

  /* buttons */
  .btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--space-8);min-height:var(--btn-h);padding:0 var(--space-24);border-radius:var(--radius-full);
    font-size:var(--text-small);font-weight:var(--weight-semibold);white-space:nowrap;
    transition:transform var(--motion-feedback) var(--ease-press), background-color var(--motion-state) var(--ease-flow), color var(--motion-state) var(--ease-flow), box-shadow var(--motion-state) var(--ease-flow)}
  .btn .i{width:16px;height:16px;transition:transform var(--motion-state) var(--ease-flow)}
  .btn.primary{background:var(--color-accent);color:var(--color-on-accent)}
  .btn.primary:hover{box-shadow:var(--shadow-lift)}
  .btn.primary:hover .i{transform:translate(2px, -2px)}
  .btn.second{background:var(--color-fill);color:var(--color-ink)}
  .btn.second:hover{background:var(--color-hair)}
  .btn.icon-only{width:var(--btn-h);padding:0;background:var(--color-fill)}
  .btn.icon-only:hover{background:var(--color-hair)}
  .btn[aria-pressed="true"] .i{fill:currentColor}
  .btn:active{transform:scale(0.96)}
  .btn:disabled,.btn[aria-disabled="true"]{opacity:0.45;pointer-events:none}
  .btn.is-loading{color:transparent;position:relative;pointer-events:none}
  .btn.is-loading::after{content:"";position:absolute;width:18px;height:18px;border-radius:50%;border:2px solid var(--color-on-accent);border-right-color:transparent;animation:spin 700ms linear infinite}
  .btn-quiet{display:inline-flex;align-items:center;min-height:36px;padding:0 var(--space-12);border-radius:var(--radius-full);font-size:var(--text-meta);font-weight:var(--weight-semibold);color:var(--color-accent);
    transition:background-color var(--motion-state) var(--ease-flow), transform var(--motion-feedback) var(--ease-press)}
  .btn-quiet:hover{background:var(--color-accent-wash)}
  .btn-quiet:active{transform:scale(0.96)}
  .btn-quiet:disabled{color:var(--color-ink-3);background:none}
  .link{color:var(--color-accent);font-weight:var(--weight-semibold);white-space:nowrap;background:linear-gradient(currentColor, currentColor) 0 100% / 0 1.5px no-repeat;transition:background-size var(--motion-state) var(--ease-flow)}
  .link:hover{background-size:100% 1.5px}
  .icon-btn{width:var(--btn-h);height:var(--btn-h);display:grid;place-items:center;border-radius:var(--radius-full);color:var(--color-ink-2);flex:none;transition:background-color var(--motion-state) var(--ease-flow), transform var(--motion-feedback) var(--ease-press)}
  .icon-btn:hover{background:var(--color-fill);color:var(--color-ink)}
  .icon-btn:active{transform:scale(0.92)}

  /* tile: the bento cell. One depth strategy: a lighter surface on the canvas, no border, no resting shadow. */
  .tile{position:relative;min-width:0;display:flex;flex-direction:column;gap:var(--space-16);background:var(--tile-bg);border-radius:var(--tile-radius);padding:var(--tile-pad)}
  .tile-h{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-12);flex-wrap:wrap}
  .tile-h h2{font-size:var(--text-tile);font-weight:var(--weight-bold);letter-spacing:-0.015em;line-height:var(--leading-snug)}
  .aside{font-size:var(--text-meta);color:var(--color-ink-3)}
  .sub-h{font-size:var(--text-meta);font-weight:var(--weight-semibold);color:var(--color-ink-3)}
  .empty-note{font-size:var(--text-small);color:var(--color-ink-3);padding:var(--space-12) 0}
  .pill{display:inline-flex;align-items:center;gap:var(--space-4);height:28px;padding:0 var(--space-12);border-radius:var(--radius-full);font-size:var(--text-meta);font-weight:var(--weight-semibold);white-space:nowrap}
  .pill .i{width:15px;height:15px}
  .pill-hot{background:var(--color-live-wash);color:var(--color-live)}

  /* keynote number: the one measured figure a tile is about */
  .keynote{display:flex;align-items:baseline;flex-wrap:wrap;column-gap:var(--space-12);row-gap:var(--space-4)}
  .keynote b{font-size:var(--num-xl);font-weight:var(--weight-bold);letter-spacing:var(--tracking-number);line-height:1;color:var(--color-ink)}
  .keynote span{font-size:var(--text-small);color:var(--color-ink-2);font-weight:var(--weight-medium)}
  .t-lead .keynote b{font-size:var(--num-hero)}
  .t-lead .keynote span{font-size:var(--text-title)}
  .keynote.k-md b{font-size:var(--num-lg)}
  .keynote.k-sm b{font-size:var(--num-md)}
  .flash{animation:flash var(--motion-count) var(--ease-flow)}

  /* avatar: a source logo as an app-icon squircle; a monogram when no verified logo exists */
  .av{position:relative;display:inline-grid;place-items:center;flex:none;width:var(--av-md);height:var(--av-md);border-radius:var(--av-radius);overflow:hidden;
    background:oklch(var(--av-mono-bg) var(--mono-h, 250));color:oklch(var(--av-mono-ink) var(--mono-h, 250));font-weight:var(--weight-bold);font-size:var(--av-text-md);line-height:1}
  .av::after{content:attr(data-mono);grid-area:1/1}
  .av:has(.av-img)::after{content:none}
  .av-img{grid-area:1/1;width:100%;height:100%;object-fit:cover;background:var(--color-surface)}
  .av-xs{width:var(--av-xs);height:var(--av-xs);font-size:var(--av-text-xs)}
  .av-sm{width:var(--av-sm);height:var(--av-sm);font-size:var(--av-text-sm)}
  .av-lg{width:var(--av-lg);height:var(--av-lg);font-size:var(--av-text-lg)}
  .av-xl{width:var(--av-xl);height:var(--av-xl);font-size:var(--av-text-xl)}
  .av-stack{display:inline-flex;flex:none}
  .av-stack-item{display:inline-flex;border-radius:var(--av-radius);box-shadow:0 0 0 3px var(--tile-bg)}
  .av-stack-item + .av-stack-item{margin-left:-10px}

  /* lead */
  .t-lead{padding:var(--tile-pad-hero);gap:var(--space-24)}
  .lead-top{display:flex;align-items:center;gap:var(--space-16)}
  .lead-label{display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-8);min-width:0}
  .lead-src{font-size:var(--text-meta);color:var(--color-ink-2)}
  .keynote{margin-top:var(--space-8)}
  .lead-title-wrap{font-size:var(--text-lead);font-weight:var(--weight-bold);letter-spacing:var(--tracking-display);line-height:var(--leading-tight);text-wrap:balance}
  .lead-title{text-align:left;overflow-wrap:anywhere;min-width:0;background:linear-gradient(currentColor, currentColor) 0 100% / 0 2px no-repeat;transition:background-size var(--motion-state) var(--ease-flow)}
  .lead-title:hover{background-size:100% 2px}
  .lead-sum{font-size:var(--text-title);color:var(--color-ink-2);max-width:62ch;text-wrap:pretty;overflow-wrap:anywhere}
  .lead-why{font-size:var(--text-meta);color:var(--color-ink-3);max-width:62ch}
  .lead-foot{display:flex;align-items:center;gap:var(--space-32);margin-top:auto;padding-top:var(--space-8)}
  .lead-facts{display:flex;flex-direction:column;gap:var(--space-12);min-width:0;font-size:var(--text-small);color:var(--color-ink-2)}
  .lead-facts b{color:var(--color-ink)}
  .acts{display:flex;flex-wrap:wrap;gap:var(--space-8);align-items:center}
  .lead-more{display:flex;flex-direction:column;gap:var(--space-4);border-top:1px solid var(--color-hair);padding-top:var(--space-16)}
  .cov{display:flex;flex-direction:column;gap:var(--space-8)}
  .cov li{display:flex;align-items:center;gap:var(--space-8);flex-wrap:wrap;font-size:var(--text-small);background:var(--color-inset);border-radius:var(--inner-radius);padding:var(--space-12) var(--space-16)}
  .cov .pub{font-weight:var(--weight-semibold)}
  .cov .m{color:var(--color-ink-2)}
  .cov .go{margin-left:auto;color:var(--color-accent);font-weight:var(--weight-semibold);min-height:var(--btn-h);display:inline-flex;align-items:center}

  /* ring gauge */
  .ring{position:relative;display:inline-grid;place-items:center;width:var(--ring-size);height:var(--ring-size);flex:none}
  .ring svg{grid-area:1/1;width:100%;height:100%;transform:rotate(-90deg)}
  .ring circle{fill:none;stroke-width:var(--ring-stroke)}
  .ring-track{stroke:var(--color-fill)}
  .ring-val{stroke:var(--color-live);stroke-linecap:round;stroke-dasharray:var(--c);stroke-dashoffset:var(--off)}
  .ring-n{grid-area:1/1;display:flex;flex-direction:column;align-items:center;line-height:1}
  .ring-n b{font-size:var(--size-32);font-weight:var(--weight-bold);letter-spacing:var(--tracking-number)}
  .ring-n span{font-size:var(--text-micro);color:var(--color-ink-3);margin-top:var(--space-4)}

  /* rows: logo · title + meta · measure */
  .row,.repo,.hrow{position:relative;display:grid;grid-template-columns:auto minmax(0, 1fr) auto;align-items:center;gap:var(--space-12);width:100%;min-height:56px;
    padding:var(--space-8) var(--space-12);margin:0 calc(var(--space-12) * -1);width:calc(100% + var(--space-24));border-radius:var(--inner-radius);text-align:left;
    transition:background-color var(--motion-state) var(--ease-flow)}
  .row:hover,.repo:hover,.hrow:hover{background:var(--color-inset)}
  .row[aria-pressed="true"],.repo[aria-pressed="true"],.hrow[aria-pressed="true"]{background:var(--color-accent-wash)}
  .row-m{display:flex;flex-direction:column;min-width:0;gap:2px}
  .row .t,.hrow .t,.ev-row .t,.cd-m .t{font-weight:var(--weight-semibold);line-height:var(--leading-snug);overflow-wrap:anywhere;text-wrap:pretty}
  .row.c .t{font-size:var(--text-small);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  .row .k,.hrow .k,.ev-row .k,.cd-m .k,.vid .k{font-size:var(--text-meta);color:var(--color-ink-3);line-height:1.45;overflow-wrap:anywhere}
  .row .k .pub{color:var(--color-ink-2);font-weight:var(--weight-medium)}
  .row .r,.repo .r{font-size:var(--text-meta);color:var(--color-ink-3);text-align:right;white-space:nowrap;display:flex;flex-direction:column;align-items:flex-end;gap:2px}
  .row .r .mv{color:var(--color-ink);font-weight:var(--weight-semibold)}
  .is-read .t,.is-read .nm,.lead-title.is-read{color:var(--color-ink-2)}
  .is-new .t,.is-new .nm,.lead-title.is-new{font-weight:var(--weight-bold)}
  .is-skipped .t,.is-skipped .nm,.lead-title.is-skipped{color:var(--color-ink)}
  .new-mark{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--color-accent);margin-right:var(--space-8);vertical-align:0.12em;flex:none}
  .skipped-mark{display:inline-block;width:7px;height:7px;border-radius:50%;border:1.5px solid var(--color-ink-3);background:transparent;margin-right:var(--space-8);vertical-align:0.12em;box-sizing:border-box;flex:none}
  .seen-mark{display:inline-flex;align-items:center;justify-content:center;margin-right:var(--space-6);color:var(--color-ink-3);vertical-align:-0.12em;flex:none}
  .seen-mark svg,.seen-mark .i{width:13px;height:13px;stroke:currentColor;stroke-width:2.2;fill:none}
  .lead-title .new-mark,.lead-title .skipped-mark{width:10px;height:10px;vertical-align:0.15em}
  .lead-title .seen-mark{width:18px;height:18px;vertical-align:-0.1em}
  .lead-title .seen-mark svg,.lead-title .seen-mark .i{width:18px;height:18px}
  .saved-mark{display:inline-flex;margin-right:var(--space-4);color:var(--color-accent);vertical-align:-0.15em;flex:none}
  .saved-mark svg{width:14px;height:14px;fill:currentColor;stroke:currentColor;stroke-width:1.6}
  .views{display:inline-flex;align-items:center;gap:2px}
  .views .i{width:13px;height:13px}
  .stack{display:flex;flex-direction:column;gap:var(--space-4)}
  .list{display:flex;flex-direction:column;gap:var(--space-4)}
  .row-tools{display:flex;align-items:center;gap:var(--space-8)}
  .row-tools > .row,.row-tools > .repo{flex:1;min-width:0;margin-right:0;width:auto}
  .expand{align-self:flex-start;margin-top:var(--space-8)}

  /* hot */
  .hot-list{display:flex;flex-direction:column;gap:var(--space-4);counter-reset:none}
  .hrow{grid-template-columns:2.25rem auto minmax(0, 1fr) 7.5rem;min-height:72px}
  .rk{font-size:var(--size-28);font-weight:var(--weight-bold);color:var(--color-ink-3);letter-spacing:var(--tracking-number);text-align:center;line-height:1}
  .score{display:flex;flex-direction:column;align-items:flex-end;gap:var(--space-8);min-width:6rem}
  .score b{font-size:var(--text-tile);font-weight:var(--weight-bold);color:var(--color-ink);letter-spacing:var(--tracking-number);line-height:1}
  .meter{display:block;width:100%;height:6px;border-radius:var(--radius-full);background:var(--color-fill);overflow:hidden}
  .meter i{display:block;height:100%;width:100%;border-radius:inherit;background:var(--color-live);transform-origin:left;transform:scaleX(var(--v))}
  .row .score{min-width:5rem;gap:var(--space-4)} .row .score b{font-size:var(--text-body)}

  /* repo */
  .repo-hero{display:flex;align-items:center;gap:var(--space-16);text-align:left;border-radius:var(--inner-radius);transition:transform var(--motion-feedback) var(--ease-press)}
  .repo-hero .row-m{gap:var(--space-8);align-items:flex-start}
  .repo-hero .nm{font-size:var(--text-tile);font-weight:var(--weight-bold);letter-spacing:-0.015em;line-height:var(--leading-snug);overflow-wrap:anywhere}
  .repo-hero:hover .nm{color:var(--color-accent)}
  .repo-hero:active{transform:scale(0.985)}
  .own{color:var(--color-ink-3);font-weight:var(--weight-medium)}
  .repo .nm{font-weight:var(--weight-semibold);overflow-wrap:anywhere;line-height:var(--leading-snug)}
  .repo.c .nm{font-size:var(--text-small)}
  .repo .why{font-size:var(--text-meta);color:var(--color-ink-3);overflow-wrap:anywhere}
  .repo .r b{color:var(--color-ink);font-size:var(--text-small)}
  .repo-why{font-size:var(--text-small);color:var(--color-ink-2);overflow-wrap:anywhere}
  .repo-next{display:flex;flex-direction:column;gap:var(--space-4);border-top:1px solid var(--color-hair);padding-top:var(--space-12)}
  .lab{display:inline-flex;align-items:center;height:24px;padding:0 var(--space-8);border-radius:var(--radius-full);font-size:var(--text-micro);font-weight:var(--weight-semibold);white-space:nowrap;vertical-align:0.08em}
  .lab.dung-ngay{background:var(--color-ok-wash);color:var(--color-ok)}
  .lab.xao-nau{background:var(--color-warn-wash);color:var(--color-warn)}
  .lab.nghien-cuu{background:var(--color-fill);color:var(--color-ink-2)}
  .lic{display:inline-flex;align-items:center;gap:2px;color:var(--color-warn);font-weight:var(--weight-medium)}
  .lic .i{width:13px;height:13px}
  /* install command: copy with one press; the icon swaps to a check */
  .cmd{display:flex;align-items:center;gap:var(--space-8);background:var(--color-inset);border-radius:var(--inner-radius);padding:var(--space-4) var(--space-4) var(--space-4) var(--space-16);min-width:0}
  .cmd code{flex:1;min-width:0;font-family:var(--family-mono);font-size:var(--text-meta);color:var(--color-ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .cmd-copy{display:inline-flex;align-items:center;gap:var(--space-4);min-height:var(--btn-h);padding:0 var(--space-12);border-radius:var(--radius-8);font-size:var(--text-meta);font-weight:var(--weight-semibold);color:var(--color-accent);
    transition:background-color var(--motion-state) var(--ease-flow), transform var(--motion-feedback) var(--ease-press)}
  .cmd-copy:hover{background:var(--color-accent-wash)}
  .cmd-copy:active{transform:scale(0.94)}
  .cmd-copy .i{width:16px;height:16px;transition:opacity var(--motion-state) var(--ease-flow), transform var(--motion-state) var(--ease-flow)}
  .cmd-copy svg:nth-of-type(2){position:absolute;opacity:0;transform:scale(0.5)}
  .cmd-copy{position:relative}
  .cmd-copy.is-done{color:var(--color-ok)}
  .cmd-copy.is-done svg:nth-of-type(1){opacity:0;transform:scale(0.5)}
  .cmd-copy.is-done svg:nth-of-type(2){opacity:1;transform:none;stroke-width:2.4}

  /* live and upcoming */
  .state{display:inline-flex;align-items:center;gap:var(--space-8);font-size:var(--text-meta);color:var(--color-ink-3)}
  .state.on{color:var(--color-live);font-weight:var(--weight-semibold)}
  .pulse{position:relative;width:10px;height:10px;border-radius:50%;background:var(--color-hair);flex:none}
  .pulse.on{background:var(--color-live)}
  .pulse.on::after{content:"";position:absolute;inset:0;border-radius:50%;background:var(--color-live);animation:pulse var(--duration-1800) var(--ease-flow) infinite}
  .media{display:flex;flex-direction:column;gap:var(--space-12);text-align:left;border-radius:var(--inner-radius)}
  .media.is-live{background:var(--color-live-wash);padding:var(--space-16)}
  .media strong{font-weight:var(--weight-semibold);line-height:var(--leading-snug)}
  .media-cap{display:flex;flex-direction:column;gap:var(--space-4)}
  .thumb{position:relative;display:block;border-radius:var(--inner-radius);overflow:hidden;aspect-ratio:16 / 9;background:var(--color-fill)}
  .thumb img{width:100%;height:100%;object-fit:cover;transition:transform var(--motion-count) var(--ease-flow)}
  .play{position:absolute;left:var(--space-12);bottom:var(--space-12);width:40px;height:40px;border-radius:50%;display:grid;place-items:center;background:var(--color-media-scrim);color:var(--color-on-media);
    transition:transform var(--motion-state) var(--ease-flow)}
  .play .i{fill:currentColor;stroke:none;width:20px;height:20px}
  .media:hover .thumb img,.vid:hover .thumb img{transform:scale(1.04)}
  .media:hover .play,.vid:hover .play{transform:scale(1.1)}
  .live-next{display:flex;flex-direction:column;gap:var(--space-16);border-top:1px solid var(--color-hair);padding-top:var(--space-16)}
  .countdown{display:flex;gap:var(--space-16);align-items:flex-start}
  .cd-n{display:flex;flex-direction:column;align-items:flex-start;line-height:1;flex:none}
  .cd-n b{font-size:var(--num-lg);font-weight:var(--weight-bold);letter-spacing:var(--tracking-number)}
  .cd-n span{font-size:var(--text-meta);color:var(--color-ink-2);margin-top:var(--space-4);white-space:nowrap}
  .cd-m{display:flex;flex-direction:column;gap:var(--space-4);min-width:0;align-items:flex-start}
  .cd-m .t,.ev-row .t{text-align:left}
  .cd-m .t:hover,.ev-row .t:hover{color:var(--color-accent)}
  .cd-m .calbtn{margin-top:var(--space-8);margin-left:calc(-1 * var(--cd-shift, 0px))}
  .ev-row{display:grid;grid-template-columns:auto minmax(0, 1fr);align-items:center;gap:var(--space-12)}
  .ev-row .calbtn{grid-column:1 / -1}
  .datebadge{width:var(--av-md);height:var(--av-md);border-radius:var(--av-radius);background:var(--color-inset);display:flex;flex-direction:column;align-items:center;justify-content:center;line-height:1}
  .datebadge b{font-size:var(--text-title);font-weight:var(--weight-bold)}
  .datebadge span{font-size:var(--datebadge-text);color:var(--color-ink-3);margin-top:2px}
  /* calendar split control: Google Calendar link + .ics file */
  .calbtn{display:inline-flex;align-items:stretch;border-radius:var(--radius-full);background:var(--color-fill);overflow:hidden;flex:none;max-width:100%}
  .calbtn-g,.calbtn-ics{display:inline-flex;white-space:nowrap;align-items:center;gap:var(--space-8);min-height:40px;padding:0 var(--space-16);font-size:var(--text-meta);font-weight:var(--weight-semibold);
    transition:background-color var(--motion-state) var(--ease-flow), color var(--motion-state) var(--ease-flow)}
  .calbtn-g{color:var(--color-accent)}
  .calbtn-g .i{width:16px;height:16px}
  .calbtn-ics{color:var(--color-ink-2);box-shadow:inset 1px 0 0 var(--color-hair);padding:0 var(--space-12)}
  .calbtn-g:hover,.calbtn-ics:hover{background:var(--color-hair);color:var(--color-ink)}
  .calbtn-g:active,.calbtn-ics:active{background:var(--color-accent-wash)}
  .calbtn :focus-visible{outline-offset:-3px;border-radius:var(--radius-full)}

  /* new */
  .new-top{display:flex;align-items:flex-end;gap:var(--space-24);flex-wrap:wrap}
  .new-hist{flex:1;min-width:180px;display:flex;flex-direction:column;gap:var(--space-4)}
  .hist{display:grid;grid-template-columns:repeat(24, minmax(0, 1fr));align-items:end;gap:3px;height:56px}
  .hist-bar{display:block;height:max(3px, calc(var(--h) * 100%));border-radius:3px;background:var(--color-fill);transform-origin:bottom}
  .hist-bar.is-new{background:var(--color-accent)}
  .hist-bar.is-zero{background:var(--color-fill)}
  .hist-axis{display:flex;justify-content:space-between;font-size:var(--text-micro);color:var(--color-ink-3)}

  /* listen */
  .vid2{display:grid;grid-template-columns:repeat(2, minmax(0, 1fr));gap:var(--space-16)}
  .vids{display:grid;grid-template-columns:repeat(auto-fill, minmax(220px, 1fr));gap:var(--space-24)}
  .vid{display:flex;flex-direction:column;gap:var(--space-8);text-align:left;min-width:0}
  .vid .t{font-size:var(--text-small);font-weight:var(--weight-semibold);line-height:var(--leading-snug);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  .vid:hover .t{color:var(--color-accent)}

  /* sources tile */
  .dots{display:flex;flex-wrap:wrap;gap:6px}
  .dots i{width:12px;height:12px;border-radius:4px;background:var(--color-ok)}
  .dots i.warn{background:var(--color-warn)}
  .src-live{display:block;font-size:var(--text-meta);color:var(--color-ink-2);margin-top:auto}

  /* chapters */
  .ch{gap:var(--space-16)}
  .ch-h{margin-bottom:var(--space-8)}
  .ch-h h2{font-size:var(--text-feature);font-weight:var(--weight-bold);letter-spacing:var(--tracking-display);line-height:var(--leading-tight);text-wrap:balance}
  .ch-h .aside{margin-top:var(--space-4)}
  /* The count is the title's quiet tail: same baseline, smaller, muted; the figure itself in the accent. */
  .ch-c{display:inline-block;margin-left:var(--space-4);font-size:var(--text-meta);font-weight:var(--weight-medium);letter-spacing:normal;color:var(--color-ink-3);white-space:nowrap}
  .ch-c .num{font-size:var(--text-small);font-weight:var(--weight-bold);color:var(--color-accent)}
  .chips{display:flex;flex-wrap:wrap;gap:var(--space-8)}
  .chip{display:inline-flex;align-items:center;gap:var(--space-8);min-height:var(--btn-h);padding:0 var(--space-16);border-radius:var(--radius-full);background:var(--color-fill);font-size:var(--text-small);font-weight:var(--weight-medium);
    transition:background-color var(--motion-state) var(--ease-flow), color var(--motion-state) var(--ease-flow), transform var(--motion-feedback) var(--ease-press)}
  .chip .i{width:0;opacity:0;margin-right:calc(var(--space-8) * -1);transition:width var(--motion-state) var(--ease-flow), opacity var(--motion-state) var(--ease-flow), margin var(--motion-state) var(--ease-flow);stroke-width:2.4}
  .chip .n{color:var(--color-ink-3)}
  .chip:hover{background:var(--color-hair)}
  .chip:active{transform:scale(0.96)}
  .chip[aria-pressed="true"]{background:var(--color-ink);color:var(--color-surface)}
  .chip[aria-pressed="true"] .n{color:inherit;opacity:0.7}
  .chip[aria-pressed="true"] .i{width:16px;opacity:1;margin-right:0}
  .chips-note{font-size:var(--text-meta);color:var(--color-ink-3)}
  /* Repository list: one segmented track, like Apple's segmented control. The chosen segment is a raised thumb
     (surface on the fill track; one step lighter than the track in dark mode). Phones get a 44px touch height. */
  .seg{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0, 1fr);padding:calc(var(--space-4) / 2);border-radius:var(--radius-full);background:var(--color-fill);width:100%;max-width:calc(var(--space-96) * 4)}
  .seg-b{position:relative;min-height:calc(var(--chip-h) - var(--space-4));padding:0 var(--space-8);text-align:center;border-radius:var(--radius-full);font-size:var(--text-meta);font-weight:var(--weight-medium);color:var(--color-ink-2);line-height:var(--leading-snug);
    transition:background-color var(--motion-state) var(--ease-flow), color var(--motion-state) var(--ease-flow), box-shadow var(--motion-state) var(--ease-flow)}
  .seg-b:hover{color:var(--color-ink)}
  .seg-b:active:not([aria-pressed="true"]){background:var(--color-hair)}
  .seg-b[aria-pressed="true"]{background:var(--color-surface);color:var(--color-ink);font-weight:var(--weight-semibold);box-shadow:0 1px 2px oklch(var(--shadow-tint) / 0.14), 0 2px 6px oklch(var(--shadow-tint) / 0.06)}
  [data-theme="dark"] .seg-b[aria-pressed="true"]{background:var(--color-hair)}
  @media (prefers-color-scheme: dark){ :root:not([data-theme="light"]) .seg-b[aria-pressed="true"]{background:var(--color-hair)} }
  .seg-b:focus-visible{outline-offset:0;border-radius:var(--radius-full)}
  /* Window (or total): plain words; the chosen one turns blue, the colour this page keeps for "chosen". */
  .tabs-t{display:flex;flex-wrap:wrap;column-gap:var(--space-16);margin-top:calc(var(--space-4) * -1)}
  .tab-t{position:relative;min-height:var(--space-24);font-size:var(--text-meta);font-weight:var(--weight-medium);color:var(--color-ink-3);transition:color var(--motion-state) var(--ease-flow)}
  .tab-t:hover{color:var(--color-ink)}
  .tab-t:active{color:var(--color-ink-2)}
  .tab-t[aria-pressed="true"]{color:var(--color-accent);font-weight:var(--weight-semibold)}
  .tab-t::before{content:"";position:absolute;inset:calc(var(--space-4) * -1) calc(var(--space-8) * -1)}
  @media (max-width: 767px), (pointer: coarse){
    .seg-b{min-height:calc(var(--btn-h) - var(--space-4))}
    .seg-b::before{content:"";position:absolute;inset:calc(var(--space-4) / -2) 0}
    .tab-t::before{inset:calc((var(--btn-h) - var(--space-24)) / -2) calc(var(--space-8) * -1)}
  }
  .src-sub{font-size:var(--text-meta);font-weight:var(--weight-semibold);color:var(--color-ink-2);margin-top:var(--space-8)}
  .srcgrid{display:grid;grid-template-columns:repeat(auto-fill, minmax(260px, 1fr));gap:var(--space-4) var(--space-24)}
  .srow{display:grid;grid-template-columns:auto minmax(0, 1fr) auto;gap:var(--space-12);align-items:center;font-size:var(--text-small);min-height:40px}
  .srow a{font-weight:var(--weight-semibold);overflow-wrap:anywhere}
  .srow a:hover{color:var(--color-accent)}
  .srow .err{display:block;font-size:var(--text-micro);color:var(--color-warn)}
  .warn-t{color:var(--color-warn)}

  /* fresh-snapshot button, toast */
  .fresh{position:fixed;left:50%;top:calc(var(--bar-h) + var(--space-12));transform:translateX(-50%);z-index:35}
  .fresh-btn{display:inline-flex;align-items:center;gap:var(--space-8);min-height:var(--btn-h);padding:0 var(--space-24);border-radius:var(--radius-full);background:var(--color-accent);color:var(--color-on-accent);font-weight:var(--weight-semibold);font-size:var(--text-small);box-shadow:var(--shadow-lift);animation:drop var(--motion-arrive) var(--ease-flow) both}
  .toast{position:fixed;left:50%;bottom:var(--space-32);transform:translateX(-50%);z-index:60;pointer-events:none}
  .toast span{display:block;background:var(--color-ink);color:var(--color-surface);padding:var(--space-12) var(--space-24);border-radius:var(--radius-full);font-size:var(--text-small);font-weight:var(--weight-medium);box-shadow:var(--shadow-lift);animation:rise var(--motion-arrive) var(--ease-flow) both}
  .toast span.out{animation:fade-out var(--motion-state) var(--ease-exit) both}

  /* detail sheet */
  .scrim{position:fixed;inset:0;z-index:40;background:var(--color-scrim);opacity:0;visibility:hidden;transition:opacity var(--motion-state) var(--ease-flow), visibility 0s linear var(--motion-state)}
  .scrim.on{opacity:1;visibility:visible;transition:opacity var(--motion-open) var(--ease-flow)}
  .sheet{position:fixed;z-index:45;top:var(--space-12);right:var(--space-12);bottom:var(--space-12);width:calc(var(--sheet-w) - var(--space-24));display:flex;flex-direction:column;
    background:var(--color-surface);border-radius:var(--tile-radius);box-shadow:var(--shadow-sheet);visibility:hidden;transform:translateX(calc(100% + 32px));
    transition:transform var(--motion-state) var(--ease-exit), visibility 0s linear var(--motion-state)}
  .sheet.on{transform:none;visibility:visible;transition:transform var(--motion-open) var(--ease-flow)}
  .sheet-top{display:flex;align-items:center;justify-content:space-between;gap:var(--space-8);padding:var(--space-12) var(--space-12) 0 var(--space-32)}
  .sheet-top .k{font-size:var(--text-meta);font-weight:var(--weight-semibold);color:var(--color-ink-3);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .sheet-body{overflow-y:auto;overscroll-behavior:contain;padding:var(--space-8) var(--space-32) var(--space-48);display:flex;flex-direction:column;gap:var(--space-16)}
  .sheet-body.swap{animation:fade-in var(--motion-state) var(--ease-flow)}
  .sh-head{display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-16)}
  .sheet h2{font-size:var(--text-feature);font-weight:var(--weight-bold);line-height:var(--leading-tight);letter-spacing:var(--tracking-display);text-wrap:balance;overflow-wrap:anywhere}
  .sheet .sum{color:var(--color-ink-2);text-wrap:pretty;overflow-wrap:anywhere}
  .sh-score{display:flex;align-items:center;gap:var(--space-24);background:var(--color-inset);border-radius:var(--inner-radius);padding:var(--space-16);font-size:var(--text-small);color:var(--color-ink-2)}
  .sh-score .ring{--ring-size:88px}
  .facts{display:grid;grid-template-columns:auto 1fr;gap:var(--space-8) var(--space-16);font-size:var(--text-small)}
  .facts dt{color:var(--color-ink-3)}
  .hint{font-size:var(--text-meta);color:var(--color-ink-3)}
  .tlh{font-size:var(--text-meta);font-weight:var(--weight-semibold);color:var(--color-ink-2);margin-top:var(--space-8)}
  .tl{display:flex;flex-direction:column;gap:var(--space-12)}
  .tl li{display:flex;gap:var(--space-12);align-items:flex-start;font-size:var(--text-small)}
  .tl-m{display:flex;flex-direction:column;gap:2px;min-width:0}
  .tl .when{font-size:var(--text-meta);color:var(--color-ink-3)}
  .tl a{font-weight:var(--weight-semibold);overflow-wrap:anywhere}
  .tl a:hover{color:var(--color-accent)}
  .tl .m{font-size:var(--text-meta);color:var(--color-ink-2)}
  .tl-d{color:var(--color-accent);font-size:var(--text-meta)}
  .sig{display:flex;flex-direction:column;gap:2px;font-size:var(--text-meta)}

  /* keyboard dialog */
  .keys{border:0;border-radius:var(--tile-radius);padding:var(--space-24) var(--space-32) var(--space-32);background:var(--color-surface);color:var(--color-ink);box-shadow:var(--shadow-sheet);width:min(420px, calc(100vw - 32px))}
  .keys::backdrop{background:var(--color-scrim)}
  .keys-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-16)}
  .keys h2{font-size:var(--text-tile);font-weight:var(--weight-bold)}
  .keys dl{display:grid;grid-template-columns:auto 1fr;gap:var(--space-12) var(--space-16);font-size:var(--text-small);align-items:center}

  /* bottom tab bar (phone) */
  .tabs{display:none}
  @media (max-width: 767px){
    .tabs{position:fixed;left:0;right:0;bottom:0;z-index:30;display:grid;grid-template-columns:repeat(5, 1fr);background:var(--color-surface);box-shadow:0 -1px 0 var(--color-hair);padding-bottom:env(safe-area-inset-bottom)}
    .tabs a{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;min-height:56px;font-size:var(--text-micro);color:var(--color-ink-3)}
    .tabs a[aria-current="true"]{color:var(--color-accent)}
    .tabs .num{position:absolute;top:6px;left:calc(50% + 6px);min-width:18px;height:18px;padding:0 5px;border-radius:var(--radius-full);background:var(--color-accent);color:var(--color-on-accent);font-size:var(--tab-badge-text);display:grid;place-items:center}
    .sheet{top:auto;left:0;right:0;bottom:0;width:auto;max-height:88dvh;border-radius:var(--tile-radius) var(--tile-radius) 0 0;transform:translateY(100%)}
    .sheet-body{padding:var(--space-8) var(--space-24) calc(var(--space-48) + env(safe-area-inset-bottom))}
    .sheet-top{padding-left:var(--space-24)}
    .hrow{grid-template-columns:1.75rem auto minmax(0, 1fr);grid-template-areas:"rk av m" ". . s"}
    .hrow .rk{font-size:var(--size-21)}
    .hrow .score{grid-column:3;flex-direction:row-reverse;align-items:center;justify-content:flex-end;min-width:0}
    .hrow .score .meter{width:96px}
    .lead-foot{flex-direction:column;align-items:flex-start;gap:var(--space-16)}
    .vid2{grid-template-columns:minmax(0, 1fr)}
    .countdown{flex-direction:column;gap:var(--space-8)}
    .ev-row .calbtn{grid-column:1 / -1}
    .row,.repo{grid-template-columns:auto minmax(0, 1fr)}
    .row .r,.repo .r{grid-column:2;align-items:flex-start;flex-direction:row;gap:var(--space-8);text-align:left}
    .srcgrid{grid-template-columns:minmax(0, 1fr)}
    .toast{bottom:calc(72px + env(safe-area-inset-bottom))}
  }

  /* skeleton */
  /* The snapshot decides whether a warning precedes the board. Keep its loading geometry without painting
     tiles at the wrong position; renderBoard and showError reveal the result by clearing is-loading. */
  .board.is-loading{visibility:hidden;position:relative}
  .board.is-loading > .sr{visibility:visible}
  /* Static HTML survives a failed module graph or disabled JavaScript. Taking
     it out of flow keeps the skeleton geometry and successful render intact. */
  .board.is-loading .reader-fallback{visibility:visible;position:absolute;top:0;left:0;width:100%}
  .sk-tile{min-height:220px}
  .t-lead.sk-tile{min-height:560px}
  .sk{border-radius:var(--radius-8);background:var(--color-fill);animation:breathe 1.6s var(--ease-flow) infinite alternate}
  .sk-av{width:var(--av-xl);height:var(--av-xl);border-radius:var(--av-radius)}
  .sk-num{height:96px;width:46%;border-radius:var(--radius-12)}
  .sk-title{height:36px}
  .sk-line{height:14px}
  .sk-row{height:52px;border-radius:var(--radius-12)}
  .sk-media{aspect-ratio:16 / 9;border-radius:var(--radius-12)}
  .breath{animation:breathe 2.4s var(--ease-flow) infinite alternate}
}

/* ---------------------------------------------------------------- motion
   Spec (chot-chon-loc.md, 02/10): a new tile 300ms, sheet open 350ms / close 250ms, numbers 600ms,
   View Transitions for a new snapshot with @starting-style as the fallback, skeleton while loading.
   Reduced motion keeps only a 150ms fade. */
@layer motion{
  @keyframes tile-in{from{opacity:0;transform:translateY(16px) scale(0.985)}to{opacity:1;transform:none}}
  @keyframes rise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
  @keyframes drop{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
  @keyframes fade-in{from{opacity:0}to{opacity:1}}
  @keyframes fade-out{from{opacity:1}to{opacity:0}}
  @keyframes flash{0%{color:var(--color-accent)}100%{color:inherit}}
  @keyframes pulse{0%{transform:scale(1);opacity:0.6}100%{transform:scale(2.6);opacity:0}}
  @keyframes breathe{from{opacity:1}to{opacity:0.5}}
  @keyframes spin{to{transform:rotate(360deg)}}
  @keyframes ring-draw{from{stroke-dashoffset:var(--c)}}
  @keyframes grow-x{from{transform:scaleX(0)}}
  @keyframes grow-y{from{transform:scaleY(0)}}

  /* First paint of the board: tiles flow in, one after another, 300ms each, 60ms apart. */
  .board.ready > .tile{animation:tile-in var(--motion-arrive) var(--ease-flow) both;animation-delay:calc(var(--t, 0) * 60ms)}
  /* The lead takes its skeleton's place, which is already on screen, so it rises without first going transparent.
     Its headline is then the page's largest paint the moment the board renders (an element that starts at opacity 0
     does not count as LCP, so the measure fell on a late 56px logo instead). */
  .board.ready > .t-lead{animation-name:lead-in}
  @keyframes lead-in{from{transform:translateY(16px) scale(0.985)}to{transform:none}}
  .board.ready .ring-val{animation:ring-draw var(--motion-count) var(--ease-flow) both;animation-delay:200ms}
  .board.ready .meter i{animation:grow-x var(--motion-count) var(--ease-flow) both;animation-delay:240ms}
  .board.ready .hist-bar{animation:grow-y var(--motion-count) var(--ease-flow) both;animation-delay:240ms}

  /* Hover: a tile with one target lifts a little; the press is quick and small. */
  @media (hover: hover){
    .tile.t-repo:has(.repo-hero:hover),.tile.t-listen:has(.vid:hover){transform:translateY(var(--tile-hover-lift));box-shadow:var(--shadow-lift)}
    .board > .tile{transition:transform var(--motion-state) var(--ease-flow), box-shadow var(--motion-state) var(--ease-flow)}
  }

  /* A story that arrived with a new snapshot slides in. View Transitions animate the swap where supported;
     @starting-style covers browsers without them. */
  .arrive{transition:opacity var(--motion-arrive) var(--ease-flow), transform var(--motion-arrive) var(--ease-flow);transition-delay:calc(var(--i, 0) * 40ms)}
  @starting-style{ .arrive{opacity:0;transform:translateY(10px)} }
  ::view-transition-old(root),::view-transition-new(root){animation-duration:var(--motion-arrive);animation-timing-function:var(--ease-flow)}

  @media (prefers-reduced-motion: reduce){
    html{scroll-behavior:auto}
    *,*::before,*::after{animation-duration:150ms !important;animation-iteration-count:1 !important;transition-duration:150ms !important;transition-delay:0s !important}
    .board.ready > .tile,.sheet-body.swap,.toast span,.fresh-btn{animation:fade-in 150ms linear both !important}
    .board.ready > .t-lead{animation:none !important}
    .board.ready .ring-val,.board.ready .meter i,.board.ready .hist-bar,.pulse.on::after,.sk,.breath,.flash{animation:none !important}
    .sheet{transition:opacity 150ms linear, visibility 0s linear 150ms !important;transform:none !important;opacity:0}
    .sheet.on{opacity:1;transition:opacity 150ms linear !important}
    /* The rule above gives every element a 150ms transition of "all", which includes the visibility the sheet's
       children inherit: the close button stayed hidden for 150ms after opening and could not take focus.
       The same applies to the board and its tiles when clearing is-loading on first paint. */
    .sheet *{transition-property:none !important}
    .board, .board *{transition-property:none !important}
    .tile,.btn,.chip,.theme .i,.cmd-copy .i,.thumb img,.play,.repo-hero{transform:none !important}
    .arrive{transform:none}
    @starting-style{ .arrive{opacity:0;transform:none} }
    ::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){animation-duration:150ms !important;animation-timing-function:linear !important}
    ::view-transition-group(*){animation-name:none !important}
  }
}
@layer components{
  @media (min-width: 2200px){ .when-line{display:inline} }
}
@layer components{
  .src-live .dot{margin-right:var(--space-8);vertical-align:0.05em}
  .repo.c{grid-template-columns:auto minmax(0, 1fr);min-height:52px}
  .repo.c .k{font-size:var(--text-meta);color:var(--color-ink-3)}
  .repo.c .k b{color:var(--color-ink)}
  .countdown{flex-wrap:wrap}
  .countdown .calbtn{flex-basis:100%}
  @media (min-width: 1280px){
    .bar{gap:var(--space-16)}
    .src-state .w{display:none}
    .nav a{padding:var(--space-8) 6px}
  }
}
@layer components{
  .countdown{display:grid;grid-template-columns:auto minmax(0, 1fr);column-gap:var(--space-16);row-gap:var(--space-12);align-items:start}
  .countdown .calbtn,.ev-row .calbtn{grid-column:1 / -1;justify-self:start;flex-basis:auto}
}
/* Bar responsiveness lives in the components layer, where the bar's own rules are, so the media queries win. */
@layer components{
  @media (max-width: 1099px){ .nav{display:none} }
  @media (max-width: 767px){
    .bar{gap:var(--space-8)}
    .when-line,.src-state{display:none}
    .bar > .theme{margin-left:auto}
  }
}
/* Touch floor: small text links and the brand keep their look but get a 44px hit area. */
@layer components{
  .link,.brand,.cd-m .t,.ev-row .t{position:relative}
  .link::after,.brand::after,.cd-m .t::after,.ev-row .t::after{content:"";position:absolute;inset:-14px -6px}
  .calbtn-g,.calbtn-ics{min-height:var(--btn-h)}
  .btn-quiet{min-height:var(--btn-h)}
}
/* Machine-translated titles: the Vietnamese reads first; the original sits under it, small, labelled "dịch máy". */
@layer components{
  .orig{display:block;font-size:var(--text-meta);font-weight:var(--weight-regular);color:var(--color-ink-3);line-height:1.4;overflow-wrap:anywhere;text-align:left;letter-spacing:normal}
  .orig .mt{display:inline-block;margin-right:6px;padding:0 6px;border-radius:var(--radius-full);background:var(--color-mt-bg);color:var(--color-mt-ink);font-size:var(--text-micro);font-weight:var(--weight-semibold);line-height:18px;vertical-align:1px;white-space:nowrap}
  .row.c .orig,.hrow .orig,.vid .orig,.media .orig,.ev-row .orig{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .row:not(.c) .orig{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  .lead-orig{font-size:var(--text-small);margin-top:calc(var(--space-16) * -1)}
  .sh-t{display:flex;flex-direction:column;gap:var(--space-4);min-width:0}
  /* At 375px the lead's label moves under the logos instead of running past the tile's edge. */
  .lead-top{flex-wrap:wrap}
  .lead-label{flex:1 1 240px}
  .lead-label .pill{white-space:normal;height:auto;min-height:28px;padding-block:var(--space-4);max-width:100%}
}
/* Desktop: the lead spans two rows, so it can be taller than its own content. The spare height is shared between
   its blocks instead of sitting as one hole above the score and buttons. */
@layer components{
  @media (min-width: 1280px){
    .t-lead{justify-content:space-between}
    .t-lead .lead-foot{margin-top:0}
  }
}

/* Production fixes measured on the rendered page (plans/reports/san-ui-claude.md). */
@layer components{
  /* "Sắp diễn ra": the event row on its own line, its calendar control under the title. On a narrow chapter
     (two columns at 768-1279px, or a phone) the dates move under the title, as every row does on a phone. */
  .ev-list{gap:var(--space-8);container-type:inline-size}
  .ev-item{display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-4)}
  .ev-item > .calbtn{margin-left:calc(var(--av-md) + var(--space-12))}
  @container (max-width: 440px){
    .ev-item > .row{grid-template-columns:auto minmax(0, 1fr)}
    .ev-item > .row .r{grid-column:2;align-items:flex-start;flex-direction:row;gap:var(--space-8);text-align:left;white-space:normal}
    .ev-item > .calbtn{margin-left:0}
  }

  /* Source list: the whole row is the link's hit area, at least 44px high (was the 22px line of text). */
  .srow{position:relative;min-height:var(--btn-h)}
  .srow a::after{content:"";position:absolute;inset:0;border-radius:var(--radius-8)}
  .srow a:focus-visible{outline:none}
  .srow a:focus-visible::after{outline:var(--focus-ring);outline-offset:0}

  /* Old data: one quiet line above the board, in the warning colour the source dots already use. */
  .stale{display:flex;align-items:flex-start;gap:var(--space-8);margin:0 0 var(--space-16);padding:var(--space-12) var(--space-16);
    border-radius:var(--inner-radius);background:var(--color-warn-wash);color:var(--color-ink);font-size:var(--text-small);text-wrap:pretty}
  .stale .i{color:var(--color-warn);margin-top:2px}


  /* The disclosure adds no boxes to the wide-screen flex layout: its children keep their original gaps. */
  .lead-details{display:contents}
  .lead-disclosure{display:none}

  /* Story kind: a neutral tag with its own shape, so "Thảo luận", "Mô hình", "Bài viết" differ at a glance by icon
     and word, never by colour alone. Same fill as the other chips; the word in ink-2, the shape in full ink. */
  .kind{display:inline-flex;align-items:center;gap:3px;margin-right:var(--space-8);padding:0 7px 0 5px;border-radius:var(--radius-full);
    background:var(--color-fill);color:var(--color-ink-2);font-size:var(--text-micro);font-weight:var(--weight-semibold);line-height:18px;
    vertical-align:1px;white-space:nowrap}
  .kind .i{width:13px;height:13px;color:var(--color-ink);flex:none}
  .facts .kind{margin-right:0}

  /* "Mới" tile: marking everything as seen lives with the count it resets, not in the header. */
  .new-foot{display:flex;justify-content:flex-end;margin-top:auto}
  .new-foot .btn-quiet{display:inline-flex;align-items:center;gap:var(--space-4)}
  .new-foot .btn-quiet .i{width:15px;height:15px}
  .new-foot .btn-quiet[aria-disabled="true"]{color:var(--color-ink-3);cursor:default}

  /* Tablet bar (768-1099px, no nav): the words beside the numbers go, as they already do at 1280px and up, so the
     theme button stays inside the screen. The numbers and their aria-label stay. */
  @media (min-width: 768px) and (max-width: 1099px){
    .bar{gap:var(--space-16)}
    .src-state .w{display:none}
  }

  /* Phone lead: the complete headline and its measured context first, supporting information one tap away. */
  @media (max-width: 767px){
    .t-lead{gap:var(--space-12)}
    .t-lead .lead-top{gap:var(--space-12);align-items:flex-start;flex-wrap:nowrap}
    .t-lead .lead-top .av{width:var(--av-sm);height:var(--av-sm);font-size:var(--av-text-sm)}
    .t-lead .lead-label{flex:1 1 0;gap:var(--space-8)}
    .t-lead .lead-label .pill{font-size:var(--text-micro);padding:var(--space-4) var(--space-8)}
    .t-lead .lead-label .pill .i{flex:none}
    .t-lead .lead-src{overflow-wrap:anywhere}
    .t-lead .keynote{margin-top:0;column-gap:var(--space-8)}
    .t-lead .keynote b{font-size:var(--num-md)}
    .t-lead .keynote span{font-size:var(--text-small)}
    .t-lead .lead-title-wrap{font-size:var(--text-tile);line-height:var(--leading-snug);text-wrap:pretty}
    .t-lead .lead-title{min-height:var(--btn-h)}
    .lead-disclosure{display:flex;align-items:center;justify-content:space-between;gap:var(--space-8)}
    .lead-toggle{gap:var(--space-8);margin-left:auto;min-height:var(--btn-h);font-size:var(--text-small)}
    .lead-toggle .i{width:var(--space-16);height:var(--space-16);transition:transform var(--motion-state) var(--ease-flow)}
    .lead-toggle[aria-expanded="true"] .i{transform:rotate(45deg)}
    .t-lead .lead-details{display:none}
    .t-lead.is-expanded .lead-details{display:flex;flex-direction:column;gap:var(--space-16);padding-top:var(--space-16);border-top:1px solid var(--color-hair)}
    .lead-details .lead-orig{margin-top:0}
    .lead-details .lead-sum{font-size:var(--text-body)}
    .cov{gap:var(--space-4)}
    .cov li{display:grid;grid-template-columns:auto minmax(0, 1fr) auto;align-items:center;column-gap:var(--space-8);row-gap:0;padding:var(--space-4) var(--space-4) var(--space-4) var(--space-12)}
    .cov li > .av{grid-column:1;grid-row:1}
    .cov li > .pub{grid-column:2;grid-row:1}
    .cov li > .faint{grid-column:2;grid-row:2;font-size:var(--text-meta)}
    .cov li > .m{grid-column:2;grid-row:3;font-size:var(--text-meta)}
    .cov li > .go{grid-column:3;grid-row:1 / span 3;margin-left:0;padding:0 var(--space-12)}
    .t-lead .lead-foot{flex-direction:row;flex-wrap:wrap;align-items:center;gap:var(--space-12) var(--space-16)}
    .t-lead .lead-foot .ring{--ring-size:72px;--ring-stroke:8px}
    .t-lead .lead-foot .ring-n b{font-size:var(--text-tile)}
    .t-lead .lead-facts{display:contents}
    .t-lead .lead-facts > p{flex:1 1 160px;min-width:0}
    .t-lead .lead-facts > .acts{flex-basis:100%}
  }
}
