/* Tokens are lifted verbatim from the plan's mockup-binhchon.html -- same
   names, same light values, deliberately no parallel set (MASTER-PLAN §4).
   The dark block below redefines those same tokens rather than introducing
   new ones, which is what lets this project keep the repo's cross-cutting
   dark-mode convention (CLAUDE.md "Dark mode") without forking the palette. */
:root {
  color-scheme: light dark;

  /* Colors */
  --paper: #fafafa;
  --surface: #ffffff;
  --ink: #18181b;
  --ink-2: #62626b;
  /* Was #a1a1aa, which measured 2.46:1 on --paper -- well under the 4.5:1
     WCAG AA needs for text. This token carries hint text, placeholders, clock
     labels and the footer, so it is real copy, not decoration. 4.63:1. */
  --ink-3: #71717a;
  --line: #e4e4e7;
  --line-strong: #d4d4d8;
  /* A form control's border is the only thing that identifies it here -- the
     field background (--surface) is 1.02:1 against the page. WCAG 1.4.11
     wants 3:1 for that boundary; --line is 1.22:1 and stays for decorative
     hairlines only. 3.25:1. */
  --control-border: #8e8e96;
  /* Text/icon colour on a filled --seal button. Split from plain white so
     dark mode can flip it: there the accent is light, and white on it is
     3.41:1. */
  --on-seal: #ffffff;
  --seal: #c9362b;
  --seal-soft: #fbeae8;
  --seal-hover: #b22e24;
  /* #16a34a was only 2.99:1 inside the "Đang mở" pill. 4.92:1. */
  --success: #127a38;
  --success-soft: #eaf7ee;

  /* Type */
  --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* Spacing (8px grid) */
  --sp-1: 8px;
  --sp-2: 16px;
  --sp-3: 24px;
  --sp-4: 32px;
  --sp-5: 40px;
  --sp-6: 48px;
  --sp-8: 64px;

  /* Radius */
  --r-sm: 10px;
  --r-md: 14px;
  --r-lg: 20px;
  --r-pill: 999px;

  /* Motion */
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --dur-fast: 140ms;
  --dur: 220ms;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #141417;
    --surface: #1c1c20;
    --ink: #f4f4f5;
    --ink-2: #a1a1aa;
    /* Was #71717a: 3.80:1 on the dark page, under AA for text. 5.16:1. */
    --ink-3: #87878f;
    --line: #2c2c33;
    --line-strong: #3f3f46;
    /* Lifted off #C9362B, which goes muddy on a dark ground -- same hue,
       enough luminance to clear AA against --paper as text and to read as
       the same red on a bar fill. */
    --seal: #f0574a;
    --seal-soft: #2e1a18;
    --seal-hover: #ff6d60;
    --success: #4ade80;
    --control-border: #70707b;
    /* The accent is light in dark mode, so a filled button takes dark text
       rather than white -- white on #f0574a is 3.41:1, this is 5.63:1. The
       same inversion Material 3 and Tailwind's dark themes use. */
    --on-seal: #1a0b09;
    --success-soft: #16281c;
  }
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  font-family: var(--font-ui);
  background: var(--paper);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  /* 100vh on iOS Safari counts the collapsing address bar, so a "full
     height" page is taller than the visible area and the footer sits below
     the fold until you scroll. dvh tracks the real viewport. */
  min-height: 100dvh;
  /* Stops iOS from silently scaling text up in landscape. */
  -webkit-text-size-adjust: 100%;
}

h1,
h2,
h3,
p {
  margin: 0;
}

button {
  font-family: inherit;
}

a {
  color: var(--seal);
}

.mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

input:focus-visible,
select:focus-visible,
textarea:focus-visible,
button:focus-visible,
a:focus-visible,
/* tabindex="-1" is excluded on purpose: those elements are never reachable by
   Tab, they are only focused programmatically to move a screen reader to new
   content (the dialog headings, the question after a vote). Drawing the
   focus ring there paints a red box around a heading nobody navigated to,
   which reads as an error state. */
[tabindex]:not([tabindex="-1"]):focus-visible {
  outline: 2px solid var(--seal);
  outline-offset: 2px;
}

/* Headings and panels we focus from script only, to move a screen reader to
   newly revealed content. They are not keyboard-reachable, so a ring around
   them marks nothing the user did -- it just looks like an error box drawn
   around a title. Suppressing it here is safe precisely because nothing can
   Tab to these. */
[tabindex="-1"]:focus {
  outline: none;
}

/* ============================================================== topbar */

.topbar {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  width: 100%;
  max-width: 720px;
  margin: 0 auto;
  padding: 16px 20px;
  padding-left: max(20px, env(safe-area-inset-left));
  padding-right: max(20px, env(safe-area-inset-right));
}

.topbar-brand {
  display: flex;
  align-items: center;
  text-decoration: none;
  color: var(--ink);
}

/* The mark is a masked shape, not an <img>, so it takes var(--ink) and
   follows light/dark without shipping two files. */
.topbar-logo {
  display: block;
  width: 24px;
  height: 24px;
  background-color: var(--ink);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-image: url("/logo.svg");
  mask-image: url("/logo.svg");
  transform: rotate(45deg);
}

.topbar-wordmark {
  color: var(--ink-2);
  text-decoration: none;
  font-size: 14px;
  font-weight: 600;
}

.topbar-wordmark:hover {
  color: var(--ink);
}

/* --- hamburger: 2 bars morphing into an X, Apple.com style ------------ */

.menu-btn {
  position: relative;
  width: 36px;
  height: 36px;
  border: none;
  background: transparent;
  border-radius: var(--r-sm);
  cursor: pointer;
  padding: 0;
}

.menu-bar {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 1.5px;
  background: var(--ink);
  border-radius: 2px;
  /* Centred with margin, not translate(-50%,-50%): combining translate with
     the open state's rotate() puts the pivot off the bar's true centre and
     the X comes out as a lopsided chevron. Known repo gotcha (CLAUDE.md #2). */
  margin: -0.75px 0 0 -8px;
  transition:
    transform var(--dur) var(--ease),
    opacity var(--dur) var(--ease);
}

.menu-bar--top {
  transform: translateY(-3px);
}

.menu-bar--bottom {
  transform: translateY(3px);
}

.menu-btn[aria-expanded="true"] .menu-bar--top {
  transform: rotate(45deg);
}

.menu-btn[aria-expanded="true"] .menu-bar--bottom {
  transform: rotate(-45deg);
}

.menu-panel {
  position: absolute;
  top: 56px;
  right: 20px;
  z-index: 50;
  min-width: 220px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: 0 12px 32px rgb(0 0 0 / 12%);
}

/* Pairs with the [hidden] attribute above -- setting display:flex on a class
   that can also carry [hidden] silently overrides the UA default and makes
   "hidden" elements visible. Known repo gotcha (CLAUDE.md #1). */
.menu-panel[hidden] {
  display: none;
}

.menu-panel-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 10px 12px;
  border: none;
  background: transparent;
  border-radius: var(--r-sm);
  font-size: 14px;
  font-weight: 500;
  color: var(--ink);
  text-decoration: none;
  cursor: pointer;
}

.menu-panel-item:hover {
  background: var(--paper);
}

.menu-panel-item.active {
  background: var(--seal-soft);
  color: var(--seal);
}

.menu-panel-action {
  color: var(--seal);
}

.menu-panel-divider {
  height: 1px;
  background: var(--line);
  margin: 6px 4px;
}

/* ================================================================ layout */

main {
  flex: 1;
  width: 100%;
  margin: 0 auto;
  padding: var(--sp-2) 20px var(--sp-6);
  padding-left: max(20px, env(safe-area-inset-left));
  padding-right: max(20px, env(safe-area-inset-right));
}

.col-narrow {
  max-width: 440px;
}

.col-normal {
  max-width: 520px;
}

.col-wide {
  max-width: 720px;
}

.footer {
  /* margin-top:auto pushes it to the bottom of the flex column; auto on the
     sides centres the block itself. Both are needed -- padding alone left the
     text stranded at the far edge of a wide viewport while every other
     element sat in a centred column.
     
     The 720px max-width and 20px padding are deliberately the same as
     .topbar's, so the footer text lines up with the logo rather than with
     whichever column width the current page happens to use (CLAUDE.md
     "Footer": left-aligned, padding matching the page container). */
  margin: auto auto 0;
  width: 100%;
  max-width: 720px;
  background: var(--paper);
  text-align: left;
  padding: 20px 20px;
  padding-left: max(20px, env(safe-area-inset-left));
  padding-right: max(20px, env(safe-area-inset-right));
  padding-bottom: calc(20px + env(safe-area-inset-bottom));
}

.footer p {
  margin: 0;
  color: var(--ink-3);
  font-size: 13px;
}

.footer a {
  color: inherit;
  text-decoration: none;
}

.footer a:hover {
  color: var(--ink);
}

/* ============================================================ components */

.btn-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 52px;
  border-radius: var(--r-md);
  border: none;
  background: var(--seal);
  color: var(--on-seal);
  font-size: 16px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition:
    transform var(--dur-fast) var(--ease),
    background var(--dur-fast) var(--ease);
}

.btn-primary:hover:not(:disabled) {
  background: var(--seal-hover);
}

.btn-primary:active:not(:disabled) {
  transform: scale(0.98);
}

.btn-primary:disabled {
  background: var(--line-strong);
  color: var(--ink-3);
  cursor: not-allowed;
}

.btn-inline {
  width: auto;
  height: 44px;
  padding: 0 var(--sp-3);
  white-space: nowrap;
}

.btn-ghost {
  border: none;
  background: transparent;
  color: var(--ink-2);
  font-size: 14px;
  font-weight: 500;
  padding: 8px 4px;
  cursor: pointer;
  border-radius: var(--r-sm);
}

.btn-ghost:hover {
  color: var(--ink);
}

.btn-link {
  border: none;
  background: transparent;
  color: var(--seal);
  font-size: inherit;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
}

.eyebrow {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: var(--sp-2);
}

.page-title {
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.015em;
}

.page-sub {
  margin-top: var(--sp-1);
  color: var(--ink-2);
  font-size: 15px;
  line-height: 1.5;
}

/* Kept as a spacer, not a rule: the gap alone separates the question from
   the options, and one less line is one less thing to look at. */
.divider {
  height: 0;
  margin: var(--sp-2) 0 var(--sp-3);
  border: none;
}

.form-error {
  margin-top: var(--sp-2);
  color: var(--seal);
  font-size: 14px;
}

.form-error[hidden] {
  display: none;
}

.disclaimer {
  margin-top: var(--sp-6);
  color: var(--ink-3);
  font-size: 12px;
  line-height: 1.6;
}

.locked-note {
  margin-top: var(--sp-3);
  padding: var(--sp-2);
  background: var(--surface);
  border-radius: var(--r-md);
  color: var(--ink-2);
  font-size: 14px;
}

/* ========================================================= create screen */

#q-input {
  width: 100%;
  /* One line. autoGrow() expands it as soon as the text needs a second, so a
     two-line floor only ever showed as dead space under a one-line prompt. */
  min-height: 1.35em;
  border: none;
  background: transparent;
  resize: none;
  overflow: hidden;
  font-family: var(--font-ui);
  font-size: 26px;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.3;
  color: var(--ink);
  padding: 0;
  outline: none;
}

#q-input::placeholder {
  color: var(--ink-3);
}

.option-row {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  margin-bottom: var(--sp-1);
}

.option-row input[type="text"] {
  flex: 1;
  min-width: 0;
  height: 48px;
  padding: 0 var(--sp-2);
  border: 1px solid var(--control-border);
  border-radius: var(--r-md);
  font-size: 15px;
  font-family: var(--font-ui);
  color: var(--ink);
  background: var(--surface);
  outline: none;
  transition: border-color var(--dur-fast) var(--ease);
}

.option-row input[type="text"]:focus {
  border-color: var(--ink);
}

.option-row input[type="text"]::placeholder {
  color: var(--ink-3);
}

.remove-option {
  width: 32px;
  height: 32px;
  border: none;
  background: transparent;
  color: var(--ink-3);
  font-size: 18px;
  cursor: pointer;
  border-radius: var(--r-sm);
  flex-shrink: 0;
}

.remove-option[hidden] {
  display: none;
}

.remove-option:hover {
  color: var(--seal);
  background: var(--seal-soft);
}

details.advanced {
  margin-top: var(--sp-3);
}

details.advanced summary {
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  color: var(--ink-2);
  list-style: none;
}

details.advanced summary::-webkit-details-marker {
  display: none;
}

details.advanced summary::before {
  content: "▸ ";
  display: inline-block;
  transition: transform var(--dur-fast) var(--ease);
}

details.advanced[open] summary::before {
  transform: rotate(90deg);
}

.adv-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  padding: var(--sp-2) 0;
  font-size: 14px;
}

.adv-row select {
  font-family: var(--font-ui);
  font-size: 14px;
  border: 1px solid var(--control-border);
  border-radius: var(--r-sm);
  padding: 6px 10px;
  background: var(--surface);
  color: var(--ink);
}

.switch {
  position: relative;
  display: block;
  width: 40px;
  height: 24px;
  flex-shrink: 0;
}

.switch-track {
  position: absolute;
  inset: 0;
  background: var(--line-strong);
  border-radius: var(--r-pill);
  transition: background var(--dur-fast) var(--ease);
  cursor: pointer;
}

.switch-track::before {
  content: "";
  position: absolute;
  width: 18px;
  height: 18px;
  left: 3px;
  top: 3px;
  background: #fff;
  border-radius: 50%;
  transition: transform var(--dur-fast) var(--ease);
  box-shadow: 0 1px 2px rgb(0 0 0 / 15%);
}

.switch input:checked + .switch-track {
  background: var(--seal);
}

.switch input:checked + .switch-track::before {
  transform: translateX(16px);
}

.switch input:focus-visible + .switch-track {
  outline: 2px solid var(--seal);
  outline-offset: 2px;
}

.cta-wrap {
  margin-top: var(--sp-4);
}

.cta-note {
  margin-top: var(--sp-2);
  font-size: 13px;
  color: var(--ink-3);
  line-height: 1.5;
}

.templates {
  margin-top: var(--sp-6);
}

.template-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
}

.chip {
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-2);
  border-radius: var(--r-pill);
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}

.chip:hover {
  border-color: var(--seal);
  color: var(--seal);
}

/* =================================== form fields ======================= */

.field {
  display: block;
  margin-top: var(--sp-3);
}

.field-label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-2);
  margin-bottom: 6px;
}

.field input {
  width: 100%;
  height: 48px;
  padding: 0 var(--sp-2);
  border: 1px solid var(--control-border);
  border-radius: var(--r-md);
  font-size: 16px;
  font-family: var(--font-ui);
  color: var(--ink);
  background: var(--surface);
  outline: none;
}

.field input:focus {
  border-color: var(--ink);
}

/* ======================================================== vote / results */

.poll-question {
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.3;
  color: var(--ink);
  /* Paired across the vote -> results swap so the question morphs in place
     instead of the screen cutting. Only one copy is ever in the tree. */
  view-transition-name: poll-question;
}

.poll-meta {
  margin-top: var(--sp-1);
  font-size: 13px;
  color: var(--ink-3);
}

.poll-meta .n {
  font-weight: 600;
  color: var(--ink-2);
}

.panel[hidden] {
  display: none;
}

.options-list {
  margin-top: var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.option-card {
  position: relative;
  display: block;
}

/* A real radio/checkbox, visually hidden -- not a div pretending to be one,
   so keyboard, screen readers and form semantics all keep working.

   Clipped rather than `opacity: 0` (which is what the mockup used): Chrome
   prunes a 1x1 opacity-0 input from the accessibility tree outright, and the
   ballot showed up with no selectable controls at all when checked with a
   real a11y-tree read. Clipping keeps the element rendered -- and therefore
   exposed and focusable -- while taking it off screen. */
.option-card input,
.switch input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.option-card .card-face {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2);
  border: 1.5px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  cursor: pointer;
  font-size: 16px;
  transition:
    border-color var(--dur-fast) var(--ease),
    background var(--dur-fast) var(--ease);
}

.option-card .dot {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 1.5px solid var(--line-strong);
  flex-shrink: 0;
  position: relative;
  transition: border-color var(--dur-fast) var(--ease);
}

.option-card input[type="checkbox"] ~ .card-face .dot {
  border-radius: 6px;
}

.option-card .dot::after {
  content: "";
  position: absolute;
  inset: 4px;
  border-radius: 50%;
  background: var(--seal);
  transform: scale(0);
  transition: transform var(--dur-fast) var(--ease);
}

.option-card input[type="checkbox"] ~ .card-face .dot::after {
  border-radius: 2px;
}

.option-card input:checked ~ .card-face {
  border-color: var(--seal);
  background: var(--seal-soft);
}

.option-card input:checked ~ .card-face .dot {
  border-color: var(--seal);
}

.option-card input:checked ~ .card-face .dot::after {
  transform: scale(1);
}

.option-card input:focus-visible ~ .card-face {
  outline: 2px solid var(--seal);
  outline-offset: 2px;
}

.sticky-cta {
  position: sticky;
  bottom: calc(var(--sp-2) + env(safe-area-inset-bottom));
  margin-top: var(--sp-4);
}

.live-badge,
.closed-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: var(--sp-2);
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.live-badge {
  color: var(--seal);
}

.closed-badge {
  color: var(--ink-3);
}

.live-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--seal);
  animation: pulse 1.8s ease-in-out infinite;
}

@keyframes pulse {
  0%,
  100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.4;
    transform: scale(0.8);
  }
}

#results-list {
  margin-top: var(--sp-3);
}

.result-row {
  margin-bottom: var(--sp-2);
}

.result-row .r-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-2);
  margin-bottom: 6px;
  font-size: 15px;
}

.result-row .r-label {
  font-weight: 500;
}

.result-row.mine .r-label::after {
  content: " ✓";
  color: var(--success);
}

.result-row .r-stat {
  font-size: 13px;
  color: var(--ink-2);
  white-space: nowrap;
}

.result-row .r-stat .pct {
  font-weight: 700;
  color: var(--ink);
  margin-left: 4px;
}

.bar-track {
  height: 10px;
  background: var(--line);
  border-radius: var(--r-pill);
  overflow: hidden;
}

.bar-fill {
  height: 100%;
  background: var(--seal);
  border-radius: var(--r-pill);
  transition: width 500ms var(--ease);
}

.confirm-line {
  margin-top: var(--sp-3);
  font-size: 13px;
  color: var(--ink-2);
}

.share-row {
  margin-top: var(--sp-4);
  display: flex;
  gap: var(--sp-1);
}

.pill-btn {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
}

.pill-btn:hover {
  border-color: var(--line-strong);
}

/* ============================================================= dashboard */

.dash-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-4);
}

.dash-head h1 {
  font-size: 22px;
  font-weight: 700;
}

.poll-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.poll-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2);
  margin-bottom: var(--sp-1);
  border-radius: var(--r-md);
  background: var(--surface);
}

.poll-item .p-q {
  flex: 1;
  min-width: 0;
  font-size: 15px;
  font-weight: 500;
  color: var(--ink);
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.poll-item .p-q:hover {
  color: var(--seal);
}

.status-pill {
  font-size: 12px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  white-space: nowrap;
}

.status-pill.open {
  background: var(--success-soft);
  color: var(--success);
}

.status-pill.closed {
  background: var(--line);
  color: var(--ink-2);
}

.p-votes {
  font-size: 13px;
  color: var(--ink-2);
  width: 74px;
  text-align: right;
  flex-shrink: 0;
  white-space: nowrap;
}

.p-date {
  font-size: 13px;
  color: var(--ink-3);
  width: 56px;
  text-align: right;
  flex-shrink: 0;
}


.empty-state {
  margin-top: var(--sp-6);
  text-align: center;
}

.empty-title {
  font-size: 17px;
  font-weight: 600;
}

.empty-sub {
  margin: var(--sp-1) 0 var(--sp-3);
  color: var(--ink-2);
  font-size: 14px;
}

/* ============================== the seal -- the one signature moment ==== */

.seal-overlay {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  z-index: 100;
  opacity: 0;
}

.seal-overlay.playing {
  opacity: 1;
}

.seal-overlay svg {
  width: 120px;
  height: 120px;
  opacity: 0;
}

.seal-overlay.playing svg {
  animation: seal-stamp 550ms var(--ease) forwards;
}

.seal-ring,
.seal-check {
  stroke: var(--seal);
}

@keyframes seal-stamp {
  0% {
    transform: scale(2.6) rotate(-18deg);
    opacity: 0;
  }
  55% {
    transform: scale(0.92) rotate(-6deg);
    opacity: 1;
  }
  75% {
    transform: scale(1.04) rotate(-8deg);
    opacity: 1;
  }
  100% {
    transform: scale(1) rotate(-8deg);
    opacity: 0;
  }
}

.toast {
  position: fixed;
  left: 50%;
  bottom: var(--sp-4);
  transform: translateX(-50%);
  z-index: 120;
  padding: 10px 18px;
  border-radius: var(--r-pill);
  background: var(--ink);
  color: var(--paper);
  font-size: 14px;
  box-shadow: 0 8px 24px rgb(0 0 0 / 20%);
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }

  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/* .p-date used to be hidden on narrow screens when it was a creation date --
   pure trivia. It now carries the delete-in countdown, which is the single
   most important thing about a row: the poll is going away. It stays. */

/* ================================== dashboard row actions ============== */

/* These were icon-only (⧉ ⊘ ✕) and nobody could be expected to know which
   glyph meant what -- "close the poll" and "delete the poll" in particular
   are one careless tap apart. Words, not glyphs. */
.row-actions {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
}

.text-btn {
  border: 1px solid transparent;
  background: transparent;
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 500;
  padding: 6px 10px;
  border-radius: var(--r-sm);
  cursor: pointer;
  white-space: nowrap;
}

.text-btn:hover {
  background: var(--line);
  color: var(--ink);
}

.text-btn--danger:hover {
  background: var(--seal-soft);
  color: var(--seal);
}

/* ============================ touch / iOS tuning ======================= */

/* iOS Safari zooms the whole page when a focused control's text is under
   16px, and then leaves it zoomed -- the create form was jumping on every
   tap into an option field. 16px everywhere is the only reliable fix; the
   visual difference from 15px is negligible. */
.option-row input[type="text"],
.adv-row select,
#bulk-input,
.field input,
#username,
#password {
  font-size: 16px;
}

@media (pointer: coarse) {
  /* 44px is Apple's minimum comfortable target. Applied only for touch
     input so the desktop layout keeps its tighter rhythm. */
  .text-btn,
  .btn-ghost,
  .chip,
  .btn-link {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }

  /* Apple asks for 44pt in both axes, and a short label like "Xoá" otherwise
     ends up a 41px-wide target. */
  .text-btn {
    min-width: 44px;
    justify-content: center;
  }

  .remove-option {
    width: 44px;
    height: 44px;
  }

  .menu-btn {
    width: 44px;
    height: 44px;
  }

  /* The question is the main way into a poll from the dashboard. */
  .poll-item .p-q {
    min-height: 44px;
    display: flex;
    align-items: center;
  }

  /* The panel is a tap-through menu on touch, so give its rows real height. */
  .menu-panel-item {
    min-height: 44px;
    display: flex;
    align-items: center;
  }

  /* The logo is a 24px mark but it is also the only way back to the hub, so
     give it a real target without changing how big the mark looks. */
  .topbar-brand {
    min-height: 44px;
    min-width: 44px;
    margin: -10px 0 -10px -10px;
    padding: 10px;
  }

  /* Same for the wordmark on the voter page's minimal header. */
  .topbar-wordmark {
    min-height: 44px;
    display: flex;
    align-items: center;
    margin: -10px -10px -10px 0;
    padding: 0 10px;
  }

  /* A <summary> is only as tall as its text (17px here). */
  details.advanced summary,
  .gate-existing summary {
    min-height: 44px;
    display: flex;
    align-items: center;
  }

  .gate-existing summary {
    justify-content: center;
  }

  /* Kill the grey flash iOS paints over any tapped element -- these all have
     their own :hover/:active treatment already. */
  a,
  button,
  label,
  summary {
    -webkit-tap-highlight-color: transparent;
  }
}

/* The credentials dialog must never exceed the screen: on a 393x852 iPhone
   with the keyboard up there is very little room, and its "Tiếp tục" button
   is the only way forward. */
.saved-card {
  max-height: calc(100dvh - 2 * var(--sp-2) - env(safe-area-inset-bottom));
  overflow-y: auto;
}

.saved-overlay {
  padding-bottom: calc(var(--sp-2) + env(safe-area-inset-bottom));
}

/* Long option labels and pasted lines must wrap rather than force the page
   into a horizontal scroll -- a poll option can be a whole sentence. */
.option-card .card-face span:last-child,
.result-row .r-label,
.poll-item .p-q {
  overflow-wrap: anywhere;
}

@media (max-width: 430px) {
  /* iPhone 14 Pro (393px) and Pro Max (430px). The results row put label and
     "N phiếu NN%" on one line, which collided once labels got long. */
  .result-row .r-top {
    flex-wrap: wrap;
    gap: 2px var(--sp-1);
  }

  .poll-question {
    font-size: 23px;
  }

  #q-input {
    font-size: 23px;
  }

  .share-row {
    flex-wrap: wrap;
  }

  .share-row .pill-btn {
    flex: 1 1 140px;
  }

  .quick-actions {
    flex-wrap: wrap;
  }

  .quick-actions .btn-primary,
  .quick-actions .pill-btn {
    flex: 1 1 100%;
  }

  .cred-row {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
  }

  .cred-row dd {
    text-align: left;
  }
}

/* ======================= desktop: nav inline, no hamburger ============= */

/* Requested. Same shape as home/'s opt-out (CLAUDE.md "Nav menu"): above the
   breakpoint the hamburger disappears and the panel becomes a plain
   horizontal row. Pure CSS -- the button and panel keep their ids, so
   menu.js needs no change and the mobile behaviour below 768px is untouched.

   The [hidden] override is mandatory, not defensive: the panel ships with the
   hidden attribute set, and a bare `display:flex` here would lose to the UA's
   [hidden]{display:none} on first paint. This is gotcha #1 in CLAUDE.md and
   it has bitten this repo more than once. */
@media (min-width: 768px) {
  .menu-btn {
    display: none;
  }

  .menu-panel,
  .menu-panel[hidden] {
    display: flex;
    position: static;
    flex-direction: row;
    align-items: center;
    gap: 2px;
    min-width: 0;
    padding: 0;
    background: transparent;
    border: none;
    box-shadow: none;
  }

  .menu-panel-item {
    width: auto;
    padding: 8px 12px;
    white-space: nowrap;
  }

  .menu-panel-divider {
    width: 1px;
    height: 20px;
    margin: 0 6px;
    background: var(--line);
  }
}

/* ========================= created / share-link card =================== */

.created-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-2);
  padding-bottom: calc(var(--sp-2) + env(safe-area-inset-bottom));
  background: rgb(0 0 0 / 45%);
  animation: overlay-in 180ms var(--ease);
}

.created-overlay[hidden] {
  display: none;
}

@keyframes overlay-in {
  from {
    opacity: 0;
  }
}

.created-card {
  width: 100%;
  max-width: 420px;
  max-height: calc(100dvh - 2 * var(--sp-2) - env(safe-area-inset-bottom));
  overflow-y: auto;
  padding: var(--sp-4) var(--sp-3) var(--sp-3);
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: 0 24px 60px rgb(0 0 0 / 30%);
  text-align: center;
  animation: card-in 240ms var(--ease);
}

@keyframes card-in {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.97);
  }
}

/* A quiet tick, not the red seal. The seal is reserved for the moment a
   vote is cast (MASTER-PLAN §4: one accent, and nothing else competes with
   it) -- reusing it here would spend that moment on the creator instead of
   on the voter. */
.created-check {
  width: 52px;
  height: 52px;
  margin: 0 auto var(--sp-2);
  border-radius: 50%;
  background: var(--success-soft);
  color: var(--success);
  display: flex;
  align-items: center;
  justify-content: center;
}

.created-check svg {
  width: 26px;
  height: 26px;
  stroke-dasharray: 30;
  stroke-dashoffset: 30;
  animation: tick-draw 420ms var(--ease) 120ms forwards;
}

@keyframes tick-draw {
  to {
    stroke-dashoffset: 0;
  }
}

.created-card h2 {
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.created-sub {
  margin-top: 6px;
  font-size: 14px;
  color: var(--ink-2);
}

/* The link is the button. One large target, so on a phone there is no small
   icon to aim at -- the whole row copies. */
.link-copy {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  width: 100%;
  min-height: 56px;
  margin-top: var(--sp-3);
  padding: 0 var(--sp-2);
  border: 1.5px solid var(--line);
  border-radius: var(--r-md);
  background: var(--paper);
  color: var(--ink);
  font-size: 15px;
  cursor: pointer;
  text-align: left;
  transition:
    border-color var(--dur-fast) var(--ease),
    background var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease);
}

.link-copy:hover {
  border-color: var(--line-strong);
}

.link-copy:active {
  transform: scale(0.985);
}

.link-copy-url {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
}

.link-copy-icon {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  position: relative;
  color: var(--ink-3);
}

.link-copy-icon svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transition:
    opacity var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease);
}

.link-copy-icon .ico-done {
  opacity: 0;
  transform: scale(0.6);
}

/* Copied: the control itself reports the result. */
.link-copy.is-copied {
  border-color: var(--success);
  background: var(--success-soft);
}

.link-copy.is-copied .link-copy-icon {
  color: var(--success);
}

.link-copy.is-copied .ico-copy {
  opacity: 0;
  transform: scale(0.6);
}

.link-copy.is-copied .ico-done {
  opacity: 1;
  transform: scale(1);
}

.link-copy.is-failed {
  border-color: var(--seal);
  background: var(--seal-soft);
}

.link-copy-hint {
  margin-top: 8px;
  font-size: 12px;
  color: var(--ink-3);
  min-height: 1.4em;
  transition: color var(--dur-fast) var(--ease);
}

.link-copy-hint.ok {
  color: var(--success);
  font-weight: 600;
}

.link-copy-hint.warn {
  color: var(--seal);
}

/* Announced to screen readers only -- the colour change and icon swap say
   nothing to somebody who cannot see them. */
.sr-live {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.created-actions {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  margin-top: var(--sp-3);
}

/* flex-shrink:0 is load-bearing: .created-card is a scroll container with a
   max-height, and in a column flex layout that lets the browser shrink these
   buttons along the main axis -- "Xem bình chọn" collapsed to 19px tall on a
   393px viewport. min-height rather than height so a wrapped label still
   grows the button instead of overflowing it. */
.created-actions .btn-primary,
.created-actions .pill-btn {
  flex-shrink: 0;
  width: 100%;
  height: auto;
}

.created-actions .btn-primary {
  min-height: 50px;
}

.created-actions .pill-btn {
  min-height: 46px;
}

.created-again {
  margin-top: var(--sp-3);
  font-size: 13px;
  color: var(--ink-3);
  text-decoration: none;
}

.created-again:hover {
  color: var(--ink-2);
  text-decoration: underline;
}

@media (prefers-reduced-motion: reduce) {
  .created-overlay,
  .created-card,
  .created-check svg {
    animation: none;
  }

  .created-check svg {
    stroke-dashoffset: 0;
  }
}

/* ================================ loading buttons ====================== */

.btn-primary.is-loading,
.pill-btn.is-loading,
.btn-ghost.is-loading {
  gap: 10px;
  cursor: progress;
}

.spinner {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  opacity: 0.9;
  animation: spin 640ms linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* A disabled primary button loses its white text, so the ring needs the
   muted colour to stay visible against the grey fill. */
.btn-primary:disabled .spinner {
  border-color: var(--ink-3);
  border-top-color: transparent;
}

@media (prefers-reduced-motion: reduce) {
  .spinner {
    /* Still moves -- a frozen spinner says "stuck", which is the opposite of
       the message. Just slow enough not to be a strobe. */
    animation-duration: 1.8s;
  }
}

/* ======================= desktop: nav inline, no hamburger ============= */

/* Requested. Same shape as home/'s opt-out (CLAUDE.md "Nav menu"): above the
   breakpoint the hamburger disappears and the panel becomes a plain
   horizontal row. Pure CSS -- the button and panel keep their ids, so
   menu.js needs no change and the mobile behaviour below 768px is untouched.

   The [hidden] override is mandatory, not defensive: the panel ships with the
   hidden attribute set, and a bare `display:flex` here would lose to the UA's
   [hidden]{display:none} on first paint. This is gotcha #1 in CLAUDE.md and
   it has bitten this repo more than once. */
@media (min-width: 768px) {
  .menu-btn {
    display: none;
  }

  .menu-panel,
  .menu-panel[hidden] {
    display: flex;
    position: static;
    flex-direction: row;
    align-items: center;
    gap: 2px;
    min-width: 0;
    padding: 0;
    background: transparent;
    border: none;
    box-shadow: none;
  }

  .menu-panel-item {
    width: auto;
    padding: 8px 12px;
    white-space: nowrap;
  }

  .menu-panel-divider {
    width: 1px;
    height: 20px;
    margin: 0 6px;
    background: var(--line);
  }
}

/* ========================= created / share-link card =================== */

.created-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-2);
  padding-bottom: calc(var(--sp-2) + env(safe-area-inset-bottom));
  background: rgb(0 0 0 / 45%);
  animation: overlay-in 180ms var(--ease);
}

.created-overlay[hidden] {
  display: none;
}

@keyframes overlay-in {
  from {
    opacity: 0;
  }
}

.created-card {
  width: 100%;
  max-width: 420px;
  max-height: calc(100dvh - 2 * var(--sp-2) - env(safe-area-inset-bottom));
  overflow-y: auto;
  padding: var(--sp-4) var(--sp-3) var(--sp-3);
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: 0 24px 60px rgb(0 0 0 / 30%);
  text-align: center;
  animation: card-in 240ms var(--ease);
}

@keyframes card-in {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.97);
  }
}

/* A quiet tick, not the red seal. The seal is reserved for the moment a
   vote is cast (MASTER-PLAN §4: one accent, and nothing else competes with
   it) -- reusing it here would spend that moment on the creator instead of
   on the voter. */
.created-check {
  width: 52px;
  height: 52px;
  margin: 0 auto var(--sp-2);
  border-radius: 50%;
  background: var(--success-soft);
  color: var(--success);
  display: flex;
  align-items: center;
  justify-content: center;
}

.created-check svg {
  width: 26px;
  height: 26px;
  stroke-dasharray: 30;
  stroke-dashoffset: 30;
  animation: tick-draw 420ms var(--ease) 120ms forwards;
}

@keyframes tick-draw {
  to {
    stroke-dashoffset: 0;
  }
}

.created-card h2 {
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.created-sub {
  margin-top: 6px;
  font-size: 14px;
  color: var(--ink-2);
}

/* The link is the button. One large target, so on a phone there is no small
   icon to aim at -- the whole row copies. */
.link-copy {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  width: 100%;
  min-height: 56px;
  margin-top: var(--sp-3);
  padding: 0 var(--sp-2);
  border: 1.5px solid var(--line);
  border-radius: var(--r-md);
  background: var(--paper);
  color: var(--ink);
  font-size: 15px;
  cursor: pointer;
  text-align: left;
  transition:
    border-color var(--dur-fast) var(--ease),
    background var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease);
}

.link-copy:hover {
  border-color: var(--line-strong);
}

.link-copy:active {
  transform: scale(0.985);
}

.link-copy-url {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
}

.link-copy-icon {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  position: relative;
  color: var(--ink-3);
}

.link-copy-icon svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transition:
    opacity var(--dur-fast) var(--ease),
    transform var(--dur-fast) var(--ease);
}

.link-copy-icon .ico-done {
  opacity: 0;
  transform: scale(0.6);
}

/* Copied: the control itself reports the result. */
.link-copy.is-copied {
  border-color: var(--success);
  background: var(--success-soft);
}

.link-copy.is-copied .link-copy-icon {
  color: var(--success);
}

.link-copy.is-copied .ico-copy {
  opacity: 0;
  transform: scale(0.6);
}

.link-copy.is-copied .ico-done {
  opacity: 1;
  transform: scale(1);
}

.link-copy.is-failed {
  border-color: var(--seal);
  background: var(--seal-soft);
}

.link-copy-hint {
  margin-top: 8px;
  font-size: 12px;
  color: var(--ink-3);
  min-height: 1.4em;
  transition: color var(--dur-fast) var(--ease);
}

.link-copy-hint.ok {
  color: var(--success);
  font-weight: 600;
}

.link-copy-hint.warn {
  color: var(--seal);
}

/* Announced to screen readers only -- the colour change and icon swap say
   nothing to somebody who cannot see them. */
.sr-live {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.created-actions {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  margin-top: var(--sp-3);
}

/* flex-shrink:0 is load-bearing: .created-card is a scroll container with a
   max-height, and in a column flex layout that lets the browser shrink these
   buttons along the main axis -- "Xem bình chọn" collapsed to 19px tall on a
   393px viewport. min-height rather than height so a wrapped label still
   grows the button instead of overflowing it. */
.created-actions .btn-primary,
.created-actions .pill-btn {
  flex-shrink: 0;
  width: 100%;
  height: auto;
}

.created-actions .btn-primary {
  min-height: 50px;
}

.created-actions .pill-btn {
  min-height: 46px;
}

.created-again {
  margin-top: var(--sp-3);
  font-size: 13px;
  color: var(--ink-3);
  text-decoration: none;
}

.created-again:hover {
  color: var(--ink-2);
  text-decoration: underline;
}

@media (prefers-reduced-motion: reduce) {
  .created-overlay,
  .created-card,
  .created-check svg {
    animation: none;
  }

  .created-check svg {
    stroke-dashoffset: 0;
  }
}

/* ================================ loading buttons ====================== */

.btn-primary.is-loading,
.pill-btn.is-loading,
.btn-ghost.is-loading {
  gap: 10px;
  cursor: progress;
}

.spinner {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  opacity: 0.9;
  animation: spin 640ms linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* A disabled primary button loses its white text, so the ring needs the
   muted colour to stay visible against the grey fill. */
.btn-primary:disabled .spinner {
  border-color: var(--ink-3);
  border-top-color: transparent;
}

@media (prefers-reduced-motion: reduce) {
  .spinner {
    /* Still moves -- a frozen spinner says "stuck", which is the opposite of
       the message. Just slow enough not to be a strobe. */
    animation-duration: 1.8s;
  }
}

/* ================================= inline auth gate ==================== */

.auth-gate-card {
  text-align: left;
}

.auth-gate-card h2 {
  font-size: 19px;
  text-align: center;
}

.auth-gate-card .created-sub {
  text-align: center;
}

.auth-gate-card .quick-warn {
  margin-top: var(--sp-2);
}

.gate-existing {
  margin-top: var(--sp-3);
  border-top: 1px solid var(--line);
  padding-top: var(--sp-2);
}

.gate-existing summary {
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  color: var(--ink-2);
  list-style: none;
  text-align: center;
}

.gate-existing summary::-webkit-details-marker {
  display: none;
}

.gate-existing summary:hover {
  color: var(--ink);
}

.gate-login-btn {
  margin-top: var(--sp-3);
}

/* Credentials handed back on the success card. Amber, not red: nothing has
   gone wrong, but this is the one thing on screen that cannot be recovered
   if it is ignored. */
.new-account {
  margin-top: var(--sp-3);
  padding: var(--sp-2);
  border: 1px solid var(--line);
  border-left: 3px solid #d97706;
  border-radius: var(--r-sm);
  background: var(--paper);
  text-align: left;
}

.new-account[hidden] {
  display: none;
}

.new-account-title {
  font-size: 13px;
  font-weight: 700;
  color: #b45309;
}

.new-account .cred-list {
  margin-top: var(--sp-1);
}

.new-account .cred-row {
  padding: 6px 0;
}

.new-account .cred-row dd {
  font-size: 14px;
}

.new-account .pill-btn {
  width: 100%;
  min-height: 40px;
  margin-top: var(--sp-1);
}

.new-account-note {
  margin-top: 8px;
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink-3);
}

/* ================================= the two clocks ====================== */

/* Expiry and closing are different events and must never read as one number.
   The expiry clock is the louder of the two -- it is the one where something
   disappears. */
.clocks {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
  margin-top: var(--sp-2);
}

.clock {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  font-size: 12px;
}

.clock-label {
  color: var(--ink-3);
}

.clock-value {
  font-weight: 600;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

.clock--expiry .clock-value {
  color: var(--ink);
}

.clock.is-urgent .clock-value {
  color: var(--seal);
}

.clock.is-done .clock-value {
  color: var(--ink-3);
  font-weight: 500;
}

/* ================================== manage panel ======================= */

.manage-panel {
  margin-top: var(--sp-4);
  padding: var(--sp-2);
  border-radius: var(--r-md);
  background: var(--surface);
}

.manage-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--ink-2);
}

.manage-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
  margin-top: var(--sp-2);
}

.manage-actions .pill-btn {
  flex: 1 1 auto;
  min-height: 44px;
}

.pill-btn--danger {
  color: var(--seal);
  border-color: var(--seal-soft);
}

.pill-btn--danger:hover {
  background: var(--seal-soft);
  border-color: var(--seal);
}

.manage-note {
  margin-top: var(--sp-1);
  font-size: 12px;
  line-height: 1.6;
  color: var(--ink-3);
}

/* ============================ manage link (share card) ================= */

.manage-link {
  margin-top: var(--sp-3);
  padding: var(--sp-2);
  border: 1px solid var(--line);
  border-left: 3px solid #d97706;
  border-radius: var(--r-sm);
  background: var(--paper);
  text-align: left;
}

.manage-link[hidden] {
  display: none;
}

.manage-link-title {
  font-size: 13px;
  font-weight: 700;
  color: #b45309;
}

.manage-link-url {
  margin-top: 6px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink);
  word-break: break-all;
}

.manage-link .pill-btn {
  width: 100%;
  min-height: 40px;
  margin-top: var(--sp-1);
}

.manage-link-note {
  margin-top: 8px;
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink-3);
}

.created-expiry {
  margin-top: var(--sp-2);
  font-size: 12px;
  color: var(--ink-3);
}

.created-expiry[hidden] {
  display: none;
}

@media (prefers-color-scheme: dark) {
  .manage-link {
    border-left-color: #f59e0b;
  }

  .manage-link-title {
    color: #fbbf24;
  }
}

/* ================================== locked poll ======================== */

.locked-card {
  text-align: center;
  padding-top: var(--sp-6);
}

.locked-icon {
  width: 56px;
  height: 56px;
  margin: 0 auto var(--sp-3);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink-2);
  display: flex;
  align-items: center;
  justify-content: center;
}

.locked-icon svg {
  width: 26px;
  height: 26px;
}

.locked-card h1 {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.locked-card .page-sub {
  max-width: 34ch;
  margin-inline: auto;
}

.locked-card .field {
  text-align: left;
}

.locked-card .btn-primary {
  margin-top: var(--sp-3);
}

.locked-expiry {
  margin-top: var(--sp-4);
  font-size: 12px;
  color: var(--ink-3);
}

/* ================================ dashboard note ======================= */

.dash-note {
  margin: calc(var(--sp-4) * -1 + var(--sp-1)) 0 var(--sp-3);
  font-size: 12px;
  line-height: 1.6;
  color: var(--ink-3);
}

.poll-list[hidden],
.empty-state[hidden] {
  display: none;
}

/* ============================ advanced: stacked row ==================== */

/* The password field needs a full-width input, which the label-left/control-
   right rhythm of .adv-row cannot give it. */
.adv-row--stack {
  display: block;
}

.adv-row--stack label {
  display: block;
  margin-bottom: 6px;
}

.adv-row--stack input {
  width: 100%;
  height: 44px;
  padding: 0 12px;
  border: 1px solid var(--control-border);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 16px;
  outline: none;
}

.adv-row--stack input:focus {
  border-color: var(--ink);
}

.adv-hint {
  margin-top: 6px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-3);
}

/* ========================= dashboard rows: narrow layout =============== */

/* Restored deliberately: this block was lost when the account-era styles
   were cut out around it, which left the question column collapsing to zero
   width on any viewport under the full 720px column.
   700px, not a phone breakpoint: three labelled buttons need ~240px, and
   below the full column they squeeze the question down to nothing. */
@media (max-width: 700px) {
  .poll-item {
    flex-wrap: wrap;
    gap: 4px var(--sp-1);
  }

  /* Question on its own line, then status + count + expiry + actions share
     the second. */
  .poll-item .p-q {
    flex: 1 1 100%;
    white-space: normal;
  }

  .p-votes {
    width: auto;
    text-align: left;
  }

  .p-date {
    width: auto;
  }

  /* gap:0 was here to make three labelled buttons fit, which put "Xoá"
     directly against "Đóng" -- an irreversible action one mis-tap away from
     a reversible one. 8px is Apple's minimum separation between targets and
     the row has the width for it now that the question is on its own line. */
  .row-actions {
    margin-left: auto;
    gap: var(--sp-1);
  }

  .text-btn {
    padding: 6px 10px;
  }
}

/* ======================= bulk option entry (restored) ================== */

/* This block was lost when the account-era styles were cut out around it --
   the "Nhập nhanh" panel rendered completely unstyled. Restored with the
   accessible control border rather than the decorative hairline. */

.option-tools {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.add-option {
  margin-top: var(--sp-1);
}

.bulk-panel {
  margin-top: var(--sp-2);
  padding: var(--sp-2);
  background: var(--surface);
  border-radius: var(--r-md);
}

.bulk-panel[hidden] {
  display: none;
}

.bulk-label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-2);
  margin-bottom: 6px;
}

#bulk-input {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--control-border);
  border-radius: var(--r-sm);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 16px;
  line-height: 1.5;
  resize: vertical;
  outline: none;
}

#bulk-input:focus {
  border-color: var(--ink);
}

#bulk-input::placeholder {
  color: var(--ink-3);
}

.bulk-hint {
  margin-top: 8px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-3);
  min-height: 1.5em;
}

.bulk-hint.warn {
  color: var(--seal);
}

.bulk-actions {
  display: flex;
  gap: var(--sp-1);
  margin-top: var(--sp-2);
}

.bulk-actions .btn-primary {
  flex: 1;
  min-height: 44px;
  height: auto;
  font-size: 15px;
}

.bulk-actions .pill-btn {
  flex: 0 0 auto;
  padding: 0 var(--sp-3);
}

/* ===================== other rules lost in the same cut ================ */

.topbar--minimal {
  justify-content: space-between;
}

/* Turnstile only ever renders into an off-screen container (turnstile.js), so
   this slot exists purely to carry data-sitekey. */
.turnstile-slot,
.turnstile-slot[hidden] {
  display: none;
}

.result-row .r-count {
  font-variant-numeric: tabular-nums;
}

/* Paired with .clock--expiry; the closing clock is the quieter of the two. */
.clock--closing .clock-value {
  color: var(--ink-2);
}

/* The switch's visible track is 40x24 -- deliberately, it is a switch -- but
   the thing a finger has to hit should still be 44pt tall (Apple HIG). The
   padding extends the hit area without moving the track. */
@media (pointer: coarse) {
  .switch {
    height: 44px;
    display: flex;
    align-items: center;
  }

  .switch-track {
    top: 50%;
    bottom: auto;
    margin-top: -12px;
    height: 24px;
  }
}
