/* SaydiVoice — voice history page (/{locale}/history/).
   Private page: noindex, no assistant widget. Uses the site.css tokens
   (--text, --text2, --border, --accent…) so it cannot introduce a second palette. */

.hp-wrap{max-width:960px;margin:0 auto;padding:34px 20px 64px}
/* The rows below set display:flex, which beats the UA sheet's [hidden]{display:none}.
   Without this, "hidden" containers (skeleton, list, load-more) kept painting —
   the skeleton showed THROUGH the empty state on first load. */
.hp-wrap [hidden]{display:none !important}
.hp-head{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:12px;margin-bottom:8px}
.hp-head h1,.hp-head .hp-title{font-size:clamp(26px,4vw,36px);line-height:1.15;letter-spacing:-.02em}
.hp-count{font-size:13px;font-weight:700;color:var(--text2);background:var(--bg2);
  border:1px solid var(--border);border-radius:999px;padding:5px 12px;white-space:nowrap}


/* Toolbar: search + download all + clear all. */
.hp-tools{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:14px 0 12px}
.hp-search{flex:1 1 260px;position:relative}
.hp-search input{width:100%;padding:11px 14px 11px 38px;border:1px solid var(--border);
  border-radius:12px;font:inherit;font-size:15px;color:var(--text);background:var(--surface)}
.hp-search input:focus-visible{outline:3px solid rgba(254,101,93,.35);outline-offset:1px;border-color:var(--accent)}
.hp-search input::placeholder{color:var(--text-3)}
/* The coral button darkens on hover via an ::after scrim. With the dark theme's
   dark ink (6.2:1) an 8% black scrim drops it to 3.24:1, so dark lightens. */
:root[data-theme="dark"] .hp-btn-primary:hover:not(:disabled){background:#ff7a70;border-color:transparent}
:root[data-theme="dark"] .hp-btn-primary:hover:not(:disabled)::after{background:rgba(255,255,255,.06)}
.hp-search svg{position:absolute;left:12px;top:50%;transform:translateY(-50%);width:18px;height:18px;
  color:var(--text3);pointer-events:none}
.hp-btn{font:inherit;font-size:14px;font-weight:600;border-radius:11px;padding:10px 14px;border:1px solid var(--border);
  background:var(--surface);color:var(--text);cursor:pointer;display:inline-flex;align-items:center;gap:7px;
  transition:border-color .15s,background .15s,color .15s}
.hp-btn:hover{border-color:#dcdce0;background:var(--bg2)}
.hp-btn:focus-visible{outline:3px solid rgba(254,101,93,.35);outline-offset:1px}
.hp-btn[disabled]{opacity:.5;cursor:not-allowed}
.hp-btn-danger{color:var(--danger);border-color:#f3d6da}
.hp-btn-danger:hover{background:var(--coral-tint-2);border-color:#eab8bf}
.hp-btn-icon{width:38px;height:38px;padding:0;border-radius:10px;justify-content:center}
/* The icon SVGs carry no width/height attributes (they inherit from CSS), so
   without this rule the row's "more" control paints as an empty circle. */
.hp-btn-icon svg{width:16px;height:16px;display:block}

/* ── Playback speed (post-generation, never a new render) ────────────────────
   The list has no player surface, so the control sits in the toolbar: the value
   is readable before a clip is chosen, and reachable while one plays. It is the
   same six-step popover as the studio player's, in this page's own visual
   language (hp-btn, not the studio's pill), so the two screens agree on the
   BEHAVIOUR without the private page looking like the studio. */
.hp-rate{position:relative;flex:0 0 auto}
.hp-rate-btn{font-variant-numeric:tabular-nums;font-weight:700;gap:6px}
.hp-rate-btn svg{width:16px;height:16px;display:block;color:var(--text3)}
/* Open, or "not at 1.0x": both are states the user must be able to see without
   opening anything. The TEXT stays dark — coral-on-coral is a contrast failure
   for the one string this button exists to show. */
.hp-rate-btn[aria-expanded="true"],
.hp-rate-btn[data-active="true"]{border-color:var(--accent);background:var(--coral-tint-2);color:var(--text)}
.hp-rate-btn[aria-expanded="true"] svg,
.hp-rate-btn[data-active="true"] svg{color:var(--accent)}
.hp-rate-val{line-height:1}
/* Anchored by its RIGHT edge. In both hosts the chip sits at the right end of
   the toolbar (the search field eats the flexible space), so growing leftwards
   is what keeps the panel on screen; growing rightwards ran it off the viewport
   inside the studio's Library tab, which clipped two of the six steps. A phone
   overrides this wholesale (see the 640px block). */
.hp-rate-pop{position:absolute;top:calc(100% + 8px);right:0;z-index:30;
  width:max-content;min-width:17.5rem;max-width:min(21rem, calc(100vw - 32px));
  padding:12px;border:1px solid var(--border);border-radius:14px;background:var(--surface);
  box-shadow:var(--shadow);animation:hpPopIn .14s ease-out both}
@keyframes hpPopIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.hp-rate-pop{animation:none}}
.hp-rate-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:10px}
.hp-rate-title{margin:0;font-size:12px;font-weight:700;letter-spacing:.05em;
  text-transform:uppercase;color:var(--text3)}
.hp-rate-now{font-size:15px;font-weight:800;letter-spacing:-.01em;font-variant-numeric:tabular-nums;color:var(--text)}
/* The fine control. accent-color keeps the native hit area, keyboard steps and
   focus ring, which is what makes a range input usable with a keyboard — a
   hand-styled thumb has to re-earn all three. */
.hp-rate-slider{display:block;width:100%;margin:0 0 12px;height:22px;padding:0;
  accent-color:var(--accent);cursor:pointer}
.hp-rate-slider:focus-visible{outline:3px solid rgba(254,101,93,.35);outline-offset:3px;border-radius:999px}
/* Six steps in three columns: the popover stays short enough to sit under the
   toolbar on a phone without covering the list it belongs to. */
.hp-rate-list{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
.hp-rate-opt{justify-content:center;padding:8px 6px;font-size:13px;font-weight:700;
  font-variant-numeric:tabular-nums;border-radius:999px}
.hp-rate-opt[aria-checked="true"]{border-color:var(--text);background:var(--text);color:#fff}
.hp-rate-opt[aria-checked="true"]:hover{background:var(--text);color:#fff}
.hp-rate-hint{margin:10px 2px 0;font-size:11px;line-height:1.45;color:var(--text3)}

/* The row that is currently audible. Without it the toolbar's speed has no
   visible referent: the user cannot tell which clip a change applies to. */
.hp-item.is-playing{border-color:var(--accent);box-shadow:var(--shadow)}
.hp-item.is-playing .hp-play{opacity:1;background:rgba(254,101,93,.92)}
.hp-item.is-playing .hp-play.is-paused{background:rgba(22,21,26,.55)}

/* List. One row per record; the whole row plays on click. */
.hp-list{list-style:none;display:flex;flex-direction:column;gap:10px;margin:0;padding:0}
.hp-item{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:14px;
  border:1px solid var(--border);border-radius:16px;padding:12px 14px;background:var(--surface);
  transition:border-color .15s,box-shadow .15s}
.hp-item:hover{border-color:#e2c9c7;box-shadow:var(--shadow)}
.hp-item.is-busy{opacity:.65}
.hp-item:focus-within{border-color:var(--accent)}
.hp-av{position:relative;width:46px;height:46px;border-radius:50%;flex:none;display:grid;place-items:center}
.hp-av-bg{position:absolute;inset:0;border-radius:50%;opacity:.9}
/* The voice's own artwork when we can resolve it (studio: /samples catalogue;
   rows saved after 2026-11-07 carry the URL). Sits at .9 opacity like the colour
   fill it replaces so the play glyph stays legible. */
.hp-av-bg.is-photo{background-size:cover;background-position:center;background-repeat:no-repeat}
/* Fallback for a voice with no artwork: two initials on the voice's own colour.
   Keeps rows distinguishable without pretending to show a real face. */
.hp-av-bg.is-initial{display:grid;place-items:center;font-size:15px;font-weight:700;
  letter-spacing:.02em;color:#fff;-webkit-text-fill-color:#fff;text-transform:uppercase;
  text-shadow:0 1px 2px rgba(0,0,0,.18)}

/* Script length ("189 ký tự"), sat where the storage badge used to be. */
.hp-chars{font-variant-numeric:tabular-nums;font-weight:600;color:var(--text2)}
.hp-play{position:relative;width:46px;height:46px;border-radius:50%;border:0;cursor:pointer;
  background:rgba(22,21,26,.55);color:#fff;display:grid;place-items:center;
  opacity:0;transition:opacity .15s,background .15s}
.hp-item:hover .hp-play,.hp-play:focus-visible{opacity:1}
.hp-play:focus-visible{outline:3px solid #fff;outline-offset:-3px}
.hp-play.is-loading{opacity:1}
.hp-play svg{width:18px;height:18px}
.hp-info{min-width:0}
.hp-name{font-weight:700;font-size:15px;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hp-snippet{color:var(--text2);font-size:14px;overflow:hidden;display:-webkit-box;
  -webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.45;margin-top:2px;word-break:break-word}
.hp-meta{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:6px;font-size:12px;color:var(--text3)}
.hp-meta .hp-sep{width:3px;height:3px;border-radius:50%;background:var(--text3)}
.hp-actions{position:relative;display:flex;align-items:center;gap:4px}
.hp-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:20;min-width:200px;
  background:var(--surface);border:1px solid var(--border);border-radius:12px;box-shadow:var(--shadow);padding:6px;
  display:none;flex-direction:column;gap:2px}
.hp-menu.show{display:flex}
.hp-menu button{display:flex;align-items:center;gap:9px;width:100%;text-align:left;font:inherit;font-size:14px;
  padding:9px 10px;border:0;border-radius:9px;background:transparent;color:var(--text);cursor:pointer}
.hp-menu button:hover{background:var(--bg2)}
.hp-menu button:focus-visible{outline:3px solid rgba(254,101,93,.35);outline-offset:-2px}
.hp-menu button.danger{color:var(--danger)}
.hp-menu svg{width:16px;height:16px;flex:none;color:var(--text2)}
.hp-menu button.danger svg{color:var(--danger)}

/* Per-row error: keep the row, only say the audio could not be fetched. */
.hp-item-error{grid-column:1 / -1;font-size:13px;color:var(--danger);background:var(--coral-tint-2);
  border:1px solid #f3d6da;border-radius:10px;padding:7px 10px;margin-top:2px}

/* Empty state + loading skeleton. */
.hp-empty{border:1px dashed var(--border);border-radius:18px;padding:40px 22px;text-align:center;background:var(--bg2)}
.hp-empty h2{font-size:19px;margin-bottom:8px}
.hp-empty p{color:var(--text2);font-size:15px;max-width:52ch;margin:0 auto 18px}
.hp-skel{display:flex;flex-direction:column;gap:10px}
.hp-skel-row{height:76px;border-radius:16px;border:1px solid var(--border);
  background:linear-gradient(90deg,#fafafa,#f1f1f3,#fafafa);background-size:200% 100%;
  animation:hpShimmer 1.4s linear infinite}
@keyframes hpShimmer{from{background-position:200% 0}to{background-position:-200% 0}}
@media (prefers-reduced-motion:reduce){.hp-skel-row{animation:none}}
.hp-more{display:flex;justify-content:center;margin-top:18px}
.hp-foot-note{color:var(--text3);font-size:12px;margin-top:22px;text-align:center}

/* Dialogs (rename / confirm). Native <dialog> handles the focus trap. */
.hp-dialog{border:0;border-radius:18px;padding:0;max-width:min(440px,92vw);width:100%;
  box-shadow:0 24px 60px rgba(20,20,25,.25);color:var(--text)}
.hp-dialog::backdrop{background:rgba(22,21,26,.45)}
.hp-dialog form{padding:22px}
.hp-dialog h2{font-size:18px;margin-bottom:8px}
.hp-dialog p{color:var(--text2);font-size:14px;margin-bottom:14px}
.hp-dialog input{width:100%;padding:10px 12px;border:1px solid var(--border);border-radius:10px;
  font:inherit;font-size:15px;margin-bottom:16px}
.hp-dialog input:focus-visible{outline:3px solid rgba(254,101,93,.35);outline-offset:1px;border-color:var(--accent)}
.hp-dialog-actions{display:flex;justify-content:flex-end;gap:8px}
.hp-btn-primary{
  position:relative; isolation:isolate; overflow:hidden;
  border:0; border-radius:999px;
  color:#fff; background:#ff665e;
  font-weight:500; line-height:1; white-space:normal; max-width:100%;
  box-shadow:none; filter:drop-shadow(0 4px 10px rgba(255,102,94,.28));
  text-shadow:0 1px 1.5px rgba(120,10,10,.28);
}
.hp-btn-primary::before{
  content:""; position:absolute; inset:0; z-index:-2; border-radius:inherit; pointer-events:none;
  background-color:#ff665e; background-repeat:no-repeat;
  background-image:url(pill-lime.svg),url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='142'%20height='85'%20viewBox='-41%20-3%20142%2085'%20preserveAspectRatio='none'%20fill='none'%3e%3cdefs%3e%3cfilter%20id='pm-tex'%20x='-41'%20y='-3'%20width='142'%20height='85'%20filterUnits='userSpaceOnUse'%20color-interpolation-filters='sRGB'%3e%3cfeTurbulence%20type='fractalNoise'%20baseFrequency='0.999'%20numOctaves='3'%20seed='4033'/%3e%3cfeDisplacementMap%20in='SourceGraphic'%20scale='8'%20xChannelSelector='R'%20yChannelSelector='G'/%3e%3c/filter%3e%3cfilter%20id='pm-b'%20x='-66'%20y='-66'%20width='183.8755'%20height='162.9506'%20filterUnits='userSpaceOnUse'%20color-interpolation-filters='sRGB'%3e%3cfeGaussianBlur%20stdDeviation='8'/%3e%3c/filter%3e%3c/defs%3e%3cg%20filter='url(%23pm-tex)'%3e%3cg%20transform='matrix(0.953%200.3028%20-0.9233%200.384%2016.5773%2025.1191)'%3e%3cg%20filter='url(%23pm-b)'%3e%3cpath%20d='M%2051.8754%204.3500%20C%2051.8754%2010.8253%2037.6978%2030.9505%2024.2854%2030.9505%20C%2010.8729%2030.9505%200%2025.7013%200%2019.2260%20C%200%2012.7507%2011.8601%2011.0072%2025.2726%2011.0072%20C%2027.5346%20-2.4873%2051.8754%20-2.1251%2051.8754%204.3500%20Z'%20fill='%23FA41C9'%20fill-opacity='0.6'/%3e%3c/g%3e%3c/g%3e%3c/g%3e%3c/svg%3e"),url(pill-gold.svg),url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='267'%20height='122'%20viewBox='-119%20-39%20267%20122'%20preserveAspectRatio='none'%20fill='none'%3e%3cdefs%3e%3cfilter%20id='pr-tex'%20x='-119'%20y='-39'%20width='267'%20height='122'%20filterUnits='userSpaceOnUse'%20color-interpolation-filters='sRGB'%3e%3cfeTurbulence%20type='fractalNoise'%20baseFrequency='0.999'%20numOctaves='3'%20seed='4218'/%3e%3cfeDisplacementMap%20in='SourceGraphic'%20scale='8'%20xChannelSelector='R'%20yChannelSelector='G'/%3e%3c/filter%3e%3cfilter%20id='pr-b'%20x='-66'%20y='-66'%20width='281'%20height='179'%20filterUnits='userSpaceOnUse'%20color-interpolation-filters='sRGB'%3e%3cfeGaussianBlur%20stdDeviation='8'/%3e%3c/filter%3e%3c/defs%3e%3cg%20filter='url(%23pr-tex)'%3e%3cg%20transform='matrix(1%200%200%201%20-34%203)'%3e%3cg%20filter='url(%23pr-b)'%3e%3cpath%20d='M%20149%2029.9682%20C%20104.0814%2038.5563%20125.8917%2047.0000%2090.8689%2047.0000%20C%2055.8461%2047.0000%20-51.8578%2026.7157%2030.0540%2021.6638%20C%2050.8711%2026.2243%20110.3438%2016.3076%20116.2910%202.9153%20C%20121.3219%20-8.4132%20149%2015.9675%20149%2029.9682%20Z'%20fill='%23EA483F'%20fill-opacity='1'/%3e%3c/g%3e%3c/g%3e%3c/g%3e%3c/svg%3e");
  background-position:188.8889% 85.4167%,186.3636% 6.6667%,-42.623% 38.2979%,80.9524% 47.561%;
  background-size:130% 220%,118.3333% 212.5%,150.8333% 217.5%,222.5% 305%;
  background-blend-mode:normal,lighten,normal,normal;
}
.hp-btn-primary::after{
  content:""; position:absolute; inset:0; z-index:-1; border-radius:inherit; pointer-events:none;
  background:transparent; transition:background .12s;
}
.hp-btn-primary:hover:not(:disabled)::after{ background:rgba(0,0,0,.08); }
.hp-btn-primary:disabled::after{ background:rgba(0,0,0,.5); z-index:1; }
.hp-btn-primary:disabled{ color:#fff; background:#ff665e; box-shadow:none; filter:none; opacity:1; cursor:not-allowed; }

.hp-detail-meta{color:var(--text3);font-size:12px;margin-bottom:10px !important}
.hp-detail-text{max-height:min(50vh,380px);overflow:auto;border:1px solid var(--border);
  border-radius:12px;padding:12px 14px;background:var(--bg2);margin-bottom:16px}
.hp-detail-text p{white-space:pre-wrap;word-break:break-word;font-size:14px;color:var(--text);margin:0 !important}
.hp-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}

@media (max-width:640px){
  .hp-wrap{padding:22px 14px 48px}
  .hp-item{grid-template-columns:auto minmax(0,1fr) auto;gap:10px;padding:10px}
  .hp-av,.hp-play{width:40px;height:40px}
  .hp-play{opacity:1} /* no hover on touch */
      .hp-tools{gap:8px}
  .hp-tools .hp-btn{flex:1 1 auto;justify-content:center}
  .hp-search{flex:1 1 100%}
  /* The chip stays its natural width (it shows one short value); the two
     labelled buttons keep the rest of the row. */
  .hp-rate{flex:0 0 auto}
  .hp-rate-btn{flex:0 0 auto}
  /* On a phone the chip is the MIDDLE item of the wrapped toolbar row, so a
     popover anchored to it would hang off one edge of the screen. Anchor it to
     the toolbar instead: full width, always inside the viewport. */
  .hp-tools{position:relative}
  .hp-rate{position:static}
  .hp-rate-pop{left:0;right:0;width:auto;max-width:none}
}

/* Contrast: the empty state and the live-status line were #7d7d7d on #fafafa
   (3.94:1). Use the shared text token, which is 7.56:1 on white. */
#hpEmpty p, #hpEmpty, .hp-sr, [role="status"]{ color:var(--text-2); }


/* Keep the shared site-header CTA inside a 390px viewport on this page. */
@media (max-width:430px){
  .open-studio-btn{ padding:0 6px; font-size:12px; min-width:0; }
}

/* ── Embedded in the studio's Library view (#libHistoryPanel) ────────────────
   The studio already paints the page padding, the tab strip and the scroll
   container, so the standalone page's own rhythm is trimmed here instead of
   forking the markup. The list keeps its 960px measure. */
#libHistoryPanel .hp-wrap{padding:0 0 24px;max-width:960px}
/* The studio tab already says "Lịch sử", so the page heading is noise here (and
   it repeated the count that now lives in the toolbar). */
#libHistoryPanel .hp-head{display:none}
/* Page-level privacy note ("this page is not indexed") — meaningless inside the
   studio, where the surface is not a page. Focus mode, not a duplicate. */
#libHistoryPanel .hp-foot-note{display:none}
#libHistoryPanel .hp-tools{margin-top:2px}
