/* IBM Plex Sans Thai is loaded via a <link rel="stylesheet"> in the document
   head (see layout_head()/admin_layout head) instead of @import here — an
   @import inside a render-blocking stylesheet forces the browser to finish
   downloading and parsing this whole file before it even discovers the font
   stylesheet URL, serializing what should be a parallel fetch. */

@font-face {
  font-family: 'Inter';
  src: url('../fonts/Inter-Variable.ttf') format('truetype-variations');
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
}

@font-face {
  font-family: 'Inter';
  src: url('../fonts/Inter-Italic-Variable.ttf') format('truetype-variations');
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
}

/* ============================================================================
   DAILY QUESTION — DESIGN SYSTEM
   ศูนย์ฝึกทำข้อสอบราชการออนไลน์

   Education-tech, professional, trustworthy. Built on a royal-blue core with
   restrained accents: colour is used to carry meaning (correct, wrong, warning)
   and almost never for decoration, so the page reads as an examination tool
   rather than a game.

     1. Tokens              7. Badges & pills
     2. Reset & typography  8. Alerts & toast
     3. Layout primitives   9. Header & footer
     4. Buttons            10. Home page
     5. Forms              11. Exam runner
     6. Cards & panels     12. Admin shell
   ============================================================================ */

/* ----------------------------------------------------------------- 1. TOKENS */
:root {
  /* Native widgets — scrollbars, date pickers, form controls — follow us. */
  color-scheme: light;

  /* Brand — royal blue over a deep navy base. The navy is what carries the
     weight (footer, inverted panels, headings); the blue is only ever an
     action. Both are darker and less "web-safe bright" than a default blue,
     which is most of what separates a considered interface from a template. */
  --primary: #1c47cc;
  --primary-dark: #14329b;
  --primary-darker: #0d2270;
  --primary-hover: #1a3fb8;
  --primary-soft: #eef2ff;
  --primary-soft-2: #dde5ff;
  --primary-border: #c2d0f8;
  --primary-contrast: #ffffff;
  /* Filled controls use the gradient, not the flat colour: a single hue at a
     large size reads flat, two stops of the same hue reads lit. */
  --primary-grad: linear-gradient(160deg, #2b58e8 0%, #1c47cc 45%, #16379f 100%);

  /* Navy — the ink of the brand, for inverted surfaces */
  --navy: #0a1430;
  --navy-2: #101c3d;
  --navy-line: rgba(255, 255, 255, .09);
  --navy-fg: #ccd6ee;
  --navy-dim: #8494b5;

  /* Secondary — sky blue, for accents and the hero gradient */
  --secondary: #0ea5e9;
  --secondary-soft: #e0f2fe;
  --secondary-border: #bae6fd;

  /* Semantic */
  --success: #15a34a;
  --success-soft: #e8f7ee;
  --success-border: #b7e5c8;
  --warning: #d97706;
  --warning-soft: #fff5e6;
  --warning-border: #fcdca7;
  --danger: #dc2626;
  --danger-soft: #fdecec;
  --danger-border: #f7c3c3;
  --info: #0891b2;
  --info-soft: #e0f5fa;
  --info-border: #b6e6f0;

  /* VIP — amber. The one decorative colour in the system, reserved for
     membership so the reader learns "gold means paid" and nothing else. */
  --vip: #c2620a;
  --vip-strong: #9a4d06;
  --vip-soft: #fff6e8;
  --vip-soft-2: #fbe6c2;
  --vip-border: #f0cd94;
  --vip-gradient: linear-gradient(135deg, #f59e0b, #d97706);
  --vip-on: #ffffff;

  /* Surfaces. The canvas is a shade off-white rather than blue-grey, so white
     cards separate from it by luminance instead of by hue — the page stops
     looking tinted and the cards start looking like paper. */
  --background: #f4f6fa;
  --surface: #ffffff;
  --surface-muted: #f1f4fa;
  --surface-hover: #edf1f9;
  --surface-inverse: var(--navy);
  /* Panels that should read as lifted rather than printed on the page. */
  --surface-raised: linear-gradient(180deg, #ffffff 0%, #fcfdff 100%);

  /* Text. A deeper, cooler ink than a mid navy: the contrast between heading
     and body is what carries hierarchy once the decoration is stripped out. */
  --text: #0c1730;
  --text-muted: #56637f;
  --text-subtle: #8390aa;
  --text-inverse: #ffffff;

  /* Lines */
  --border: #e5e9f2;
  --border-strong: #cfd7e6;
  --hairline: rgba(12, 23, 48, .07);
  --focus-ring: rgba(28, 71, 204, .3);

  /* Radius */
  --radius-xs: 6px;
  --radius-sm: 10px;
  --radius: 13px;
  --radius-lg: 18px;
  --radius-xl: 26px;
  --radius-pill: 999px;

  /* Shadow. Two layers each: a tight contact shadow that seats the element on
     the page, and a wide soft one that gives it height. One layer alone is
     what makes a card look stuck on rather than raised. */
  --shadow-xs: 0 1px 2px rgba(12, 23, 48, .05);
  --shadow-sm: 0 1px 2px rgba(12, 23, 48, .05), 0 4px 12px -3px rgba(12, 23, 48, .07);
  --shadow: 0 2px 4px rgba(12, 23, 48, .04), 0 14px 30px -10px rgba(12, 23, 48, .14);
  --shadow-lg: 0 4px 10px rgba(12, 23, 48, .05), 0 30px 64px -18px rgba(12, 23, 48, .24);
  /* Hover state for anything that lifts, tinted with the brand. */
  --shadow-brand: 0 2px 6px rgba(12, 23, 48, .06), 0 18px 40px -14px rgba(28, 71, 204, .34);

  /* Spacing */
  --space-2xs: 4px;
  --space-xs: 8px;
  --space-sm: 12px;
  --space: 16px;
  --space-md: 24px;
  --space-lg: 36px;
  --space-xl: 56px;
  --space-2xl: 84px;

  /* Layout */
  --container: 1400px;
  --container-narrow: 760px;
  --header-h: 66px;

  /* Motion. Three durations and two curves: --ease for anything the reader
     asked for (it should feel immediate), --spring for anything that arrives
     on its own (it should feel like it settled rather than snapped). */
  --ease: cubic-bezier(.4, 0, .2, 1);
  --spring: cubic-bezier(.22, 1, .36, 1);
  --t-fast: 140ms var(--ease);
  --t: 220ms var(--ease);
  --t-slow: 420ms var(--spring);
  --t-reveal: 700ms var(--spring);

  /* Type */
  --font: 'Inter', 'IBM Plex Sans Thai', 'Segoe UI', system-ui, -apple-system, sans-serif;
  --font-num: 'Inter', 'IBM Plex Sans Thai', system-ui, sans-serif;
}

/* Dark palette. Only the tokens change — no component restates a colour.
   Applied when the reader chooses dark with the header switch: [data-theme="dark"] */
:root[data-theme="dark"] {
  color-scheme: dark;

  --primary: #7897ff;
  --primary-dark: #5f7ef4;
  --primary-darker: #4e6ce0;
  --primary-hover: #8ba6ff;
  --primary-soft: #1a2447;
  --primary-soft-2: #222e59;
  --primary-border: #34406f;
  --primary-contrast: #070c1c;
  --primary-grad: linear-gradient(160deg, #5f7ef4 0%, #4459d8 100%);

  --navy: #060b1a;
  --navy-2: #0b1327;
  --navy-line: rgba(255, 255, 255, .08);
  --navy-fg: #c3cee8;
  --navy-dim: #7787a8;

  --secondary: #38bdf8;
  --secondary-soft: #16293c;
  --secondary-border: #24425c;

  --success: #4ade80;
  --success-soft: #14291d;
  --success-border: #245437;
  --warning: #fbbf24;
  --warning-soft: #2c2312;
  --warning-border: #55431a;
  --danger: #f87171;
  --danger-soft: #2d1717;
  --danger-border: #5a2a2a;
  --info: #38bdf8;
  --info-soft: #16293c;
  --info-border: #24425c;

  --vip: #fbbf24;
  --vip-strong: #fcd34d;
  --vip-soft: #2b2211;
  --vip-soft-2: #3d2f14;
  --vip-border: #5d4a1f;
  --vip-gradient: linear-gradient(135deg, #f59e0b, #b45309);
  --vip-on: #1a1204;

  /* Deeper than the old palette and with more separation between the canvas
     and a card: a dark theme reads cheap when every surface is the same
     charcoal, and expensive when the elevation is legible. */
  --background: #070c1c;
  --surface: #111a33;
  --surface-muted: #18213e;
  --surface-hover: #1e2848;
  --surface-inverse: #f4f6fa;
  --surface-raised: linear-gradient(180deg, #16203c 0%, #111a33 100%);

  --text: #eaeefb;
  --text-muted: #a2adca;
  --text-subtle: #7a86a5;
  --text-inverse: #070c1c;

  --border: #232e4e;
  --border-strong: #33406b;
  --hairline: rgba(255, 255, 255, .07);
  --focus-ring: rgba(120, 151, 255, .42);

  --shadow-xs: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4), 0 4px 12px -3px rgba(0, 0, 0, .45);
  --shadow: 0 2px 4px rgba(0, 0, 0, .4), 0 14px 30px -10px rgba(0, 0, 0, .6);
  --shadow-lg: 0 4px 10px rgba(0, 0, 0, .45), 0 30px 64px -18px rgba(0, 0, 0, .75);
  --shadow-brand: 0 2px 6px rgba(0, 0, 0, .5), 0 18px 40px -14px rgba(78, 108, 224, .5);
}

/* ------------------------------------------------- 2. RESET & TYPOGRAPHY */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

body {
  margin: 0;
  font-family: var(--font);
  font-optical-sizing: auto;
  font-size: 15.5px;
  line-height: 1.7;
  color: var(--text);
  background: var(--background);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Real typographic niceties rather than the browser defaults: proportional
     figures in prose, and the font's own kerning and ligatures. */
  text-rendering: optimizeLegibility;
  font-feature-settings: 'kern' 1, 'liga' 1;
  /* A page must never scroll sideways on a phone. */
  overflow-x: hidden;
}

/* Headings carry more weight and tighter tracking than the body, and the steps
   between them are wide enough to be read as steps. Flat, evenly-sized type is
   the single clearest tell of an unfinished interface. */
h1, h2, h3, h4, h5 { margin: 0 0 var(--space-xs); line-height: 1.25; font-weight: 700; color: var(--text); }
h1 { font-size: clamp(30px, 5.2vw, 46px); letter-spacing: -.03em; font-weight: 800; }
h2 { font-size: clamp(23px, 3.6vw, 33px); letter-spacing: -.025em; font-weight: 800; }
h3 { font-size: clamp(18px, 2.4vw, 21px); letter-spacing: -.015em; }
h4 { font-size: 16.5px; letter-spacing: -.01em; }
p  { margin: 0 0 var(--space-sm); }
p:last-child { margin-bottom: 0; }

a { color: var(--primary); text-decoration: none; transition: color var(--t-fast); }
a:hover { color: var(--primary-hover); text-decoration: underline; }

img, svg, video { max-width: 100%; height: auto; }
hr { border: 0; border-top: 1px solid var(--border); margin: var(--space-md) 0; }
small { font-size: 13px; }
code, pre { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .92em; }

/* Form controls do not inherit the document font by default — the browser
   gives them its own (Arial on Windows), which has no Thai glyphs, so Thai
   text inside buttons/inputs falls back to a different system face and the
   whole control looks out of place. Inherit it back once, globally. */
button, input, select, textarea, optgroup { font-family: inherit; }

/* Every interactive element gets a visible focus ring for keyboard users. */
:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}

/* Skip link — the first stop for a keyboard or screen-reader visitor. */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--primary); color: var(--primary-contrast);
  padding: 10px 18px; border-radius: 0 0 var(--radius) 0; font-weight: 600;
}
.skip-link:focus { left: 0; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.icon { flex: 0 0 auto; vertical-align: -.15em; }
.num { font-family: var(--font-num); font-variant-numeric: tabular-nums; }

/* --------------------------------------------------- 3. LAYOUT PRIMITIVES */
/* The page's one measure. It is deliberately wide: at 1200px the content sat
   as a narrow column in the middle of a large empty canvas, which is what made
   every screen read as a dashboard rather than as a page. The gutter is part of
   the measure — on a 1365px laptop the content starts 56px from the edge, not
   180px. */
.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 56px;
}
.container-narrow { max-width: var(--container-narrow); }

/* The page's rhythm. At 84px top and bottom, two neighbouring sections put
   168px of empty page between them, which is what made the site read as a
   sequence of separate screens rather than as one page. */
.section { padding: 44px 0; }
.section-tight { padding: var(--space-md) 0; }
/* A page's last section when it ends on a panel of its own. It has no bottom
   padding because the footer's own top margin already supplies that gap, and
   two of them stacked left a band of empty page under the closing panel. */
.section-close { padding: 44px 0 0; }
/* The alternating band is a gradient with hairlines top and bottom rather than
   a flat grey block: the edges resolve into the page instead of stopping dead. */
.section-alt {
  background: linear-gradient(180deg, var(--surface-muted), color-mix(in srgb, var(--surface-muted) 45%, var(--background)));
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
}
/* The home page uses spacing and background tone to separate its sections;
   extra hairlines made the long landing page look visibly segmented. */
.hero ~ .section-alt { border-top: 0; border-bottom: 0; }
/* A full-width navy band, for the closing call to action and anywhere the page
   needs one moment of real contrast. */
.section-dark {
  position: relative; overflow: hidden;
  background:
    radial-gradient(900px 420px at 15% -20%, rgba(43, 88, 232, .38), transparent 60%),
    radial-gradient(760px 400px at 88% 120%, rgba(14, 165, 233, .22), transparent 62%),
    var(--navy);
  color: #eef2fb;
}
.section-dark h1, .section-dark h2, .section-dark h3 { color: #fff; }
.section-dark .lead, .section-dark p { color: var(--navy-fg); }
.section-dark .eyebrow {
  background: rgba(255, 255, 255, .08); border-color: var(--navy-line); color: #dce6ff;
}
.section-dark .btn-outline {
  --btn-bg: rgba(255, 255, 255, .06); --btn-fg: #eaf0ff; --btn-border: rgba(255, 255, 255, .22);
}
.section-dark .btn-outline:hover { --btn-bg: rgba(255, 255, 255, .13); color: #fff; }
/* The dark band runs straight into the footer, so it drops its own margin. */
.section-dark + .site-footer { margin-top: 0; }

.section-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--space); margin-bottom: var(--space-md); flex-wrap: wrap;
}
/* The eyebrow above a heading. A pill rather than bare text, so the label
   reads as a section marker instead of a stray line of small type. */
.eyebrow {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 12px 4px 9px; margin-bottom: 10px;
  border-radius: var(--radius-pill);
  background: var(--primary-soft); border: 1px solid var(--primary-border);
  font-size: 12.5px; font-weight: 600; color: var(--primary-dark);
  letter-spacing: .01em; line-height: 1.5;
}
.section-head h2 { margin: 0; }
/* Member and review screens open with a section head that carries the page's
   h1 rather than a full page hero, since an action sits beside it. It gets the
   page-title size here so those five screens stop each choosing their own. */
.section-head h1 { font-size: clamp(23px, 3.2vw, 30px); margin: 0; letter-spacing: -.02em; }
.section-head .lead { color: var(--text-muted); margin: 8px 0 0; max-width: 62ch; }

/* A page's opening block: eyebrow, title, one line of context, then whatever
   the page needs beside it (filters, a date chip, a call to action).
   Every listing and marketing page used to hand-roll this with inline clamp
   sizes; they all share this now so the first screen of each page matches. */
.page-hero { padding: var(--space-md) 0 var(--space); }
.page-hero h1 {
  font-size: clamp(26px, 3.8vw, 36px); margin: 0;
  letter-spacing: -.02em; line-height: 1.25;
}
.page-hero .lead {
  color: var(--text-muted); font-size: 16px; margin: 10px 0 0;
  max-width: 62ch; line-height: 1.7;
}
.page-hero-center { text-align: center; }
.page-hero-center .lead { margin-left: auto; margin-right: auto; }
.page-hero-center .row,
.page-hero-center .pills { justify-content: center; }
.page-hero .hero-meta {
  display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap; margin-top: var(--space);
}
.page-hero-center .hero-meta { justify-content: center; }

.grid { display: grid; gap: var(--space); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }

/* A main column beside a narrower aside — an exam set and its VIP panel, an
   account page and its summary. Each page wants a slightly different ratio, so
   it passes one in as --split rather than writing the whole track list out
   inline: an inline grid-template-columns cannot be overridden by a media
   query, which is why these panels stayed two columns wide on a phone and
   wrapped the aside to one word per line. Below the breakpoint the aside moves
   underneath, where it has the full width to read in. */
.grid-split {
  grid-template-columns: minmax(0, var(--split, 1.5fr)) minmax(0, 1fr);
  align-items: start;
}
@media (max-width: 860px) {
  .grid-split { grid-template-columns: minmax(0, 1fr); }
}

/* Three equal-height ways in, each ending on its own arrow rather than a
   shared footer — so a reader can compare them at a glance instead of reading
   top to bottom. */
.onboard-grid .card-link { justify-content: space-between; }
.onboard-grid .go-row {
  display: inline-flex; align-items: center; gap: 4px;
  margin-top: var(--space); font-size: 13px; font-weight: 600; color: var(--primary);
}

.stack { display: flex; flex-direction: column; gap: var(--space-sm); }
.row { display: flex; align-items: center; gap: var(--space-xs); flex-wrap: wrap; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm); flex-wrap: wrap; }
.spacer { flex: 1 1 auto; }

.text-center { text-align: center; }
.text-muted { color: var(--text-muted); }
.text-subtle { color: var(--text-subtle); }
.text-success { color: var(--success); }
.text-danger { color: var(--danger); }
.text-warning { color: var(--warning); }
.text-primary { color: var(--primary); }
/* Spacing utilities. The 4 and 5 steps were missing while the markup used them
   throughout — mb-4 in particular separated the pricing cards from the
   comparison table, so with no rule behind it the two blocks collided. */
.mt-0 { margin-top: 0; } .mt-1 { margin-top: var(--space-xs); }
.mt-2 { margin-top: var(--space); } .mt-3 { margin-top: var(--space-md); }
.mt-4 { margin-top: var(--space-lg); } .mt-5 { margin-top: var(--space-xl); }
.mb-0 { margin-bottom: 0; } .mb-1 { margin-bottom: var(--space-xs); }
.mb-2 { margin-bottom: var(--space); } .mb-3 { margin-bottom: var(--space-md); }
.mb-4 { margin-bottom: var(--space-lg); } .mb-5 { margin-bottom: var(--space-xl); }

/* A wide element (table, navigator) scrolls inside itself, never the page. */
.scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* ---------------------------------------------------------------- 4. BUTTONS */
.btn {
  --btn-bg: var(--surface);
  --btn-fg: var(--text);
  --btn-border: var(--border-strong);
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 0 18px; height: 44px;
  font-family: inherit; font-size: 15px; font-weight: 600; line-height: 1;
  color: var(--btn-fg); background: var(--btn-bg);
  border: 1px solid var(--btn-border); border-radius: var(--radius);
  cursor: pointer; text-decoration: none; white-space: nowrap;
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast), transform var(--t-fast);
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px) scale(.985); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .55; cursor: not-allowed; transform: none; }
/* A disabled button still lit up on hover, which reads as clickable — and the
   `span.btn` stand-ins used where an action is unavailable are exactly the case
   that has to look inert. Killing pointer events is what does that: each
   variant sets its own hover `--btn-bg`, so neutralising them one by one in the
   cascade would need a rule per variant and would break the next one added. */
.btn[aria-disabled="true"] { pointer-events: none; }

/* A light sweeps across a filled button on hover. It is a two-second detail
   nobody names, and its absence is most of why a flat fill looks unfinished.
   Only filled buttons get it — an outline button has nothing to light. */
.btn-primary, .btn-vip, .btn-danger, .btn-success, .btn-warning { position: relative; overflow: hidden; isolation: isolate; }
.btn-primary::after, .btn-vip::after, .btn-danger::after,
.btn-success::after, .btn-warning::after {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(105deg, transparent 35%, rgba(255, 255, 255, .3) 50%, transparent 65%);
  transform: translateX(-120%);
  transition: transform 620ms var(--ease);
}
.btn-primary:hover::after, .btn-vip:hover::after, .btn-danger:hover::after,
.btn-success:hover::after, .btn-warning:hover::after { transform: translateX(120%); }

/* The primary action carries elevation of its own: on a page of white cards it
   is the one control that should read as raised. The inset highlight along its
   top edge is what makes the fill look lit rather than painted on. */
.btn-primary {
  --btn-fg: var(--primary-contrast); --btn-border: transparent;
  background: var(--primary-grad);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .18),
    0 1px 2px rgba(12, 23, 48, .2),
    0 8px 20px -6px color-mix(in srgb, var(--primary) 55%, transparent);
  transition: box-shadow var(--t), transform var(--t-fast), filter var(--t-fast);
}
.btn-primary:hover {
  color: var(--primary-contrast); filter: brightness(1.08);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .22),
    0 2px 4px rgba(12, 23, 48, .2),
    0 14px 28px -8px color-mix(in srgb, var(--primary) 62%, transparent);
  transform: translateY(-1px);
}
.btn-primary:active { transform: translateY(0) scale(.985); }
.btn-primary:disabled, .btn-primary[aria-disabled="true"] { box-shadow: none; transform: none; }

/* Membership. Gold is never used for an ordinary action, so this button says
   "this is the paid route" before the label is read. */
.btn-vip {
  --btn-fg: var(--vip-on); --btn-border: transparent;
  background: var(--vip-gradient);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .25),
    0 1px 2px rgba(120, 60, 4, .22),
    0 8px 20px -6px rgba(217, 119, 6, .45);
  transition: box-shadow var(--t), transform var(--t-fast), filter var(--t-fast);
}
.btn-vip:hover {
  color: var(--vip-on); filter: saturate(1.08) brightness(1.06); transform: translateY(-1px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .3),
    0 2px 4px rgba(120, 60, 4, .22),
    0 14px 30px -8px rgba(217, 119, 6, .55);
}
.btn-vip:active { transform: translateY(0) scale(.985); }

.btn-secondary { --btn-bg: var(--primary-soft); --btn-fg: var(--primary-dark); --btn-border: var(--primary-border); }
.btn-secondary:hover { --btn-bg: var(--primary-soft-2); color: var(--primary-dark); }

.btn-ghost { --btn-bg: transparent; --btn-border: transparent; --btn-fg: var(--text-muted); }
.btn-ghost:hover { --btn-bg: var(--surface-hover); --btn-fg: var(--text); }

.btn-outline { --btn-bg: transparent; --btn-fg: var(--text); --btn-border: var(--border-strong); }
.btn-outline:hover { --btn-bg: var(--surface-hover); }

.btn-danger { --btn-bg: var(--danger); --btn-fg: #fff; --btn-border: var(--danger); }
.btn-danger:hover { --btn-bg: #b91c1c; --btn-border: #b91c1c; color: #fff; }

.btn-success { --btn-bg: var(--success); --btn-fg: #fff; --btn-border: var(--success); }

/* Amber: an action that resumes something already started. Every page that
   wanted this had been writing the colour inline because the class did not
   exist; it does now, and the inline copies are gone. */
.btn-warning { --btn-bg: var(--warning); --btn-fg: #fff; --btn-border: var(--warning); }
.btn-warning:hover { --btn-bg: #b45309; --btn-border: #b45309; color: #fff; }

:root[data-theme="dark"] .btn-warning { --btn-fg: #2b1c04; }
:root[data-theme="dark"] .btn-warning:hover { --btn-bg: #fcd34d; --btn-border: #fcd34d; color: #2b1c04; }

.btn-lg { height: 52px; padding: 0 26px; font-size: 16.5px; border-radius: var(--radius-lg); }
.btn-sm { height: 36px; padding: 0 13px; font-size: 13.5px; border-radius: var(--radius-sm); }
/* Row-level actions inside a dense admin table. */
.btn-xs { height: 28px; padding: 0 10px; font-size: 12px; gap: 5px; border-radius: var(--radius-xs); }
.btn-block { display: flex; width: 100%; }
.btn-icon { width: 40px; padding: 0; }

/* A button waiting on a request: the label is replaced by a spinner so the
   width does not jump, and pointer events stop, preventing a double submit. */
.btn.is-loading { color: transparent !important; pointer-events: none; position: relative; }
.btn.is-loading::after {
  content: ''; position: absolute; width: 17px; height: 17px;
  border: 2px solid currentColor; border-top-color: transparent; border-radius: 50%;
  color: var(--btn-fg); animation: spin .6s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ------------------------------------------------------------------ 5. FORMS */
.form-group { margin-bottom: var(--space); }
.form-group:last-child { margin-bottom: 0; }

label, .form-label {
  display: block; font-size: 14px; font-weight: 600;
  color: var(--text); margin-bottom: 6px;
}
.req { color: var(--danger); }

.form-control, .form-select, textarea.form-control {
  display: block; width: 100%; height: 44px; padding: 0 13px;
  font-family: inherit; font-size: 15px; color: var(--text);
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius); transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
textarea.form-control { height: auto; min-height: 110px; padding: 11px 13px; line-height: 1.6; resize: vertical; }
.form-control:focus, .form-select:focus {
  outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--focus-ring);
}
.form-control::placeholder { color: var(--text-subtle); }
.form-control:disabled, .form-select:disabled { background: var(--surface-muted); cursor: not-allowed; }
.form-control.is-invalid { border-color: var(--danger); }

.form-select {
  appearance: none; padding-right: 38px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%235d6b8a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center;
}
/* Compact fields, for a filter row or an inline table editor. */
.form-control-sm, .form-select-sm { height: 36px; padding: 0 11px; font-size: 13.5px; border-radius: var(--radius-sm); }
.form-select-sm { padding-right: 32px; background-position: right 9px center; }

.form-hint { font-size: 12.5px; color: var(--text-muted); margin-top: 5px; }
.form-error { font-size: 12.5px; color: var(--danger); margin-top: 5px; font-weight: 500; }

/* A field the error summary points at. The mark is cleared the moment the
   field is edited, so it never survives the fix it asked for. */
.form-group.is-invalid > label { color: var(--danger); }
.form-group.is-invalid .form-control,
.form-group.is-invalid .form-select,
.form-group.is-invalid [data-choices] {
  border-color: var(--danger);
  box-shadow: 0 0 0 3px var(--danger-soft);
}
/* The summary's own list: one line per problem, each a way to reach the field. */
.error-list { margin: 6px 0 0; padding-left: 18px; display: grid; gap: 3px; }
.error-list li { font-size: 13.5px; }
.error-list a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.error-list a:hover { text-decoration: none; }

.form-check { display: flex; align-items: flex-start; gap: 9px; margin-bottom: 9px; }
.form-check input { width: 17px; height: 17px; margin: 3px 0 0; accent-color: var(--primary); cursor: pointer; flex: 0 0 auto; }
.form-check label { margin: 0; font-weight: 500; cursor: pointer; }

.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--space); }

/* --------------------------------------------------------- 6. CARDS & PANELS */
.card {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
/* A card raised out of the page for one important block — the sign-in panel,
   a checkout summary, a highlighted plan. */
.card-raised { box-shadow: var(--shadow); border-color: var(--border-strong); }

/* Card headers get a faint wash so the header reads as a distinct band without
   needing a second border or a heavier grey. */
.card-head { background: linear-gradient(180deg, color-mix(in srgb, var(--surface-muted) 60%, transparent), transparent); }
.card-body { padding: var(--space-md); }
.card-body-tight { padding: var(--space); }
.card-head {
  padding: var(--space) var(--space-md);
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm); flex-wrap: wrap;
}
.card-head h3, .card-head h2 { margin: 0; font-size: 17px; }
.card-foot { padding: var(--space) var(--space-md); border-top: 1px solid var(--border); }

/* A card that is a link to somewhere. On hover it lifts, its border picks up
   the brand, and a brand-tinted shadow appears underneath — the three together
   read as "this is liftable" far more clearly than a colour change alone. */
.card-link {
  display: flex; flex-direction: column; color: inherit; text-decoration: none;
  position: relative; isolation: isolate;
  transition: border-color var(--t), box-shadow var(--t-slow), transform var(--t-slow);
}
/* A brand wash that fades in behind the content rather than a border colour
   swap, which would shift the layout by a pixel on some engines. */
.card-link::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  border-radius: inherit; opacity: 0;
  background: linear-gradient(180deg, color-mix(in srgb, var(--primary) 5%, transparent), transparent 60%);
  transition: opacity var(--t);
}
.card-link:hover {
  text-decoration: none; color: inherit;
  border-color: var(--primary-border); box-shadow: var(--shadow-brand);
  transform: translateY(-4px);
}
.card-link:hover::before { opacity: 1; }
.card-link:active { transform: translateY(-1px); }
/* The arrow on a card that has one slides forward as the card lifts. */
.card-link:hover .go-arrow { transform: translateX(4px); }
.go-arrow { transition: transform var(--t-slow); }

/* Statistic tile. The label sits above the number and the number carries the
   weight, so a row of tiles scans as figures rather than as boxes. */
.stat {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: var(--space) var(--space);
  box-shadow: var(--shadow-xs);
}
.stat .k {
  display: flex; align-items: center; gap: 7px;
  font-size: 12.5px; font-weight: 600; color: var(--text-muted);
  letter-spacing: .01em;
}
.stat .k .icon { color: var(--primary); }
.stat .v {
  font-family: var(--font-num); font-size: 29px; font-weight: 700;
  line-height: 1.15; margin-top: 7px; letter-spacing: -.02em; color: var(--text);
}
.stat .sub { font-size: 12.5px; color: var(--text-subtle); margin-top: 3px; }
/* "บ.", "คน", "รายการ" — the unit stays small so the figure keeps the weight. */
.stat .v .unit { font-size: 14px; font-weight: 600; color: var(--text-muted); }
.stat .v.is-vip { color: var(--vip); display: block; }

/* Notice — an icon, a sentence or two of state, and optionally a way to act on
   it. Used for "sign in first", "you finished today's sets", "you have one in
   progress" and so on, which had each been assembled by hand from inline
   styles and so never quite matched. The stripe carries the tone. */
.notice {
  display: flex; align-items: flex-start; gap: 14px; flex-wrap: wrap;
  background: var(--surface); border: 1px solid var(--border);
  border-left: 4px solid var(--tone, var(--primary));
  border-radius: var(--radius-lg); padding: var(--space);
  box-shadow: var(--shadow-xs);
}
.notice-success { --tone: var(--success); }
.notice-warning { --tone: var(--warning); }
.notice-vip     { --tone: var(--vip); }
.notice > .notice-icon {
  width: 44px; height: 44px; flex: 0 0 auto; border-radius: var(--radius);
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--tone, var(--primary)) 12%, transparent);
  color: var(--tone, var(--primary));
}
.notice .body { flex: 1 1 280px; min-width: 0; }
.notice .title {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  font-size: 17px; font-weight: 700; margin: 0 0 4px; line-height: 1.4;
}
.notice p { font-size: 14px; color: var(--text-muted); margin: 0; line-height: 1.7; }
.notice .actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: var(--space-sm); }
.notice-success .title { color: var(--success); }

/* A label/value list — the profile's practice summary. Hairlines between rows
   rather than a table, since there is no column relationship to show. */
.pub-stats { display: grid; margin-top: 10px; }
.pub-stats > div {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space);
  padding: 11px 0; border-bottom: 1px solid var(--border); font-size: 14.5px;
}
.pub-stats > div:last-child { border-bottom: 0; padding-bottom: 0; }
.pub-stats span { color: var(--text-muted); }

/* Empty state — every listing has one; a blank area is never shipped. */
.empty {
  text-align: center; padding: var(--space-xl) var(--space-md);
  color: var(--text-muted);
}
.empty .empty-icon {
  width: 56px; height: 56px; margin: 0 auto var(--space-sm);
  display: grid; place-items: center; border-radius: var(--radius-lg);
  background: var(--surface-muted); color: var(--text-subtle);
}
.empty h3 { font-size: 17px; color: var(--text); margin-bottom: 4px; }
.empty p { max-width: 46ch; margin: 0 auto var(--space); }

/* Progress bar */
.progress {
  height: 8px; background: var(--surface-muted);
  border-radius: var(--radius-pill); overflow: hidden;
}
.progress > span {
  display: block; height: 100%; background: var(--primary);
  border-radius: inherit; transition: width var(--t);
}
.progress.sm { height: 6px; }
.progress .bar-success { background: var(--success); }
.progress .bar-warning { background: var(--warning); }
.progress .bar-danger  { background: var(--danger); }

/* Table. Both names exist because the admin screens ask for .table-responsive
   and the public ones for .table-wrap; either way the table scrolls in place
   rather than pushing the page sideways. */
.table-wrap, .table-responsive { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table.table { width: 100%; border-collapse: collapse; font-size: 14.5px; }
.table th, .table td { padding: 11px 13px; text-align: right; border-bottom: 1px solid var(--border); }
.table th:first-child, .table td:first-child { text-align: left; }
.table th {
  font-size: 12.5px; font-weight: 600; color: var(--text-muted);
  background: var(--surface-muted); white-space: nowrap;
}
.table tbody tr:hover { background: var(--surface-hover); }
.table tbody tr:last-child td { border-bottom: 0; }

/* The row's actions stay reachable when the table is wider than the space it
   has.
 *
 * Without this the edit/duplicate/delete column is simply off the right edge:
 * .table-wrap scrolls sideways, so the buttons exist but nothing on screen
 * says so, and the primary action of every row is unreachable until somebody
 * discovers they can drag the table. Measured on the question bank at a 768px
 * viewport: the table wanted 799px inside a 721px container and the actions
 * cell ran from 605px to 816px — a right edge 79px past the visible one.
 *
 * Pinning the column to the right of its scroll container keeps it in view at
 * every width. The cells need their own opaque background, including the hover
 * one, or the scrolling columns show through them. */
.table td.actions, .table th.actions {
  position: sticky; right: 0; z-index: 1;
  background: var(--surface);
}
.table th.actions { background: var(--surface-muted); }
.table tbody tr:hover td.actions { background: var(--surface-hover); }
/* Deliberately no edge shadow. CSS cannot tell whether the table is actually
   scrolled, so a shadow here is drawn just as strongly when everything already
   fits — a permanent line implying there is more to the right when there is
   not. The opaque background is enough to separate the column on the tables
   that do scroll. */

/* `position: sticky` gives every td.actions its own stacking context, all at
   the same z-index — so an open dropdown, however high its own z-index, is
   still painted underneath the next row's actions cell, whose opaque
   background sits later in paint order and simply covers it. Lifting the
   cell that currently holds an open dropdown above its siblings is what
   makes the menu land on top instead of behind the row under it. */
.table td.actions:has(.dropdown:not([hidden])) { z-index: 30; }

/* Pagination */
.pagination { display: flex; gap: 6px; justify-content: center; flex-wrap: wrap; margin-top: var(--space-md); }
.pagination a, .pagination span {
  min-width: 40px; height: 40px; padding: 0 11px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  font-size: 14px; font-weight: 600; color: var(--text); background: var(--surface);
  font-family: var(--font-num);
}
.pagination a:hover { background: var(--surface-hover); text-decoration: none; }
.pagination .current { background: var(--primary); border-color: var(--primary); color: var(--primary-contrast); }
.pagination .disabled { opacity: .45; pointer-events: none; }

/* Breadcrumb */
.breadcrumb {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  font-size: 13px; color: var(--text-muted); padding: var(--space) 0 0;
}
.breadcrumb a { color: var(--text-muted); }
.breadcrumb a:hover { color: var(--primary); }
.breadcrumb .sep { color: var(--text-subtle); }
.breadcrumb .current { color: var(--text); font-weight: 600; }

/* -------------------------------------------------------- 7. BADGES & PILLS */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 10px; border-radius: var(--radius-pill);
  font-size: 12.5px; font-weight: 600; line-height: 1.6;
  background: var(--surface-muted); color: var(--text-muted);
  border: 1px solid transparent;
}
.badge-primary { background: var(--primary-soft); color: var(--primary-dark); border-color: var(--primary-border); }
.badge-success { background: var(--success-soft); color: var(--success); border-color: var(--success-border); }
.badge-warning { background: var(--warning-soft); color: var(--warning); border-color: var(--warning-border); }
.badge-danger, .badge-error { background: var(--danger-soft); color: var(--danger); border-color: var(--danger-border); }
.badge-info    { background: var(--info-soft);    color: var(--info);    border-color: var(--info-border); }
.badge-muted   { background: var(--surface-muted); color: var(--text-muted); border-color: var(--border); }

/* Membership marks. The soft one labels VIP content in a list; the solid one
   is the reader's own status in the header, where it has to win attention. */
.badge-vip { background: var(--vip-soft); color: var(--vip); border-color: var(--vip-border); font-weight: 700; }
.badge-vip-solid {
  background: var(--vip-gradient); color: var(--vip-on);
  border-color: transparent; font-weight: 700;
}
a.badge-vip-solid:hover { color: var(--vip-on); text-decoration: none; filter: brightness(1.06); }
.badge-lg { padding: 6px 14px; font-size: 13.5px; }

/* Filter pills */
.pills { display: flex; gap: 8px; flex-wrap: wrap; }
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 15px; border-radius: var(--radius-pill);
  font-size: 14px; font-weight: 600; color: var(--text-muted);
  background: var(--surface); border: 1px solid var(--border-strong);
  transition: all var(--t-fast); white-space: nowrap;
}
.pill:hover { color: var(--text); border-color: var(--primary-border); text-decoration: none; }
.pill.active { background: var(--primary); border-color: var(--primary); color: var(--primary-contrast); }
.pill.active:hover { color: var(--primary-contrast); }

/* --------------------------------------------------------- 8. ALERTS & TOAST */
.alert {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 13px 16px; border-radius: var(--radius);
  border: 1px solid var(--border); background: var(--surface-muted);
  font-size: 14.5px; margin-bottom: var(--space);
}
.alert .icon { margin-top: 2px; }
.alert-success { background: var(--success-soft); border-color: var(--success-border); color: var(--success); }
.alert-error, .alert-danger { background: var(--danger-soft); border-color: var(--danger-border); color: var(--danger); }
.alert-warning { background: var(--warning-soft); border-color: var(--warning-border); color: var(--warning); }
.alert-info { background: var(--info-soft); border-color: var(--info-border); color: var(--info); }
.alert strong { color: inherit; }

.toast-stack {
  position: fixed; z-index: 300; right: 16px; bottom: 16px;
  display: flex; flex-direction: column; gap: 9px;
  max-width: min(360px, calc(100vw - 32px));
}
.toast {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 15px; border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--border);
  box-shadow: var(--shadow-lg); font-size: 14.5px;
  animation: toast-in var(--t) both;
}
.toast.leaving { animation: toast-out var(--t) both; }
.toast-success { border-left: 3px solid var(--success); }
.toast-error   { border-left: 3px solid var(--danger); }
.toast-warning { border-left: 3px solid var(--warning); }
.toast-info    { border-left: 3px solid var(--info); }
@keyframes toast-in  { from { opacity: 0; transform: translateY(10px); } }
@keyframes toast-out { to   { opacity: 0; transform: translateY(6px); } }

/* Modal */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 250;
  background: rgba(12, 20, 45, .55); backdrop-filter: blur(2px);
  display: grid; place-items: center; padding: 18px;
}
.modal {
  width: 100%; max-width: 460px; max-height: calc(100vh - 36px);
  overflow-y: auto;
  background: var(--surface); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); border: 1px solid var(--border);
  animation: modal-in var(--t) both;
}
@keyframes modal-in { from { opacity: 0; transform: scale(.97) translateY(8px); } }
.modal-head { padding: var(--space-md) var(--space-md) 0; }
.modal-head h3 { margin: 0; }
.modal-body { padding: var(--space-sm) var(--space-md); color: var(--text-muted); }
.modal-foot { padding: var(--space-sm) var(--space-md) var(--space-md); display: flex; gap: 9px; justify-content: flex-end; }

/* The quieter second line: the facts of what is about to be lost. */
.modal-detail {
  margin: var(--space-sm) 0 0; padding: 9px 11px;
  border-radius: var(--radius); border: 1px solid var(--hairline);
  background: var(--surface-muted); color: var(--text);
  font-size: 13.5px; font-weight: 600;
}

/* A destructive dialog reads red before it is read at all: a top rule and a
   red heading, which is enough to change the register without turning the
   dialog into a warning poster. */
.modal.is-danger { border-color: var(--danger-border); border-top: 3px solid var(--danger); }
.modal.is-danger .modal-head h3 { color: var(--danger); }
.modal.is-danger .modal-detail { border-color: var(--danger-border); background: var(--danger-soft); }

@media (max-width: 520px) { .modal-foot { flex-direction: column-reverse; } .modal-foot .btn { width: 100%; } }

/* ------------------------------------------------------- 9. HEADER & FOOTER */
.site-header {
  position: sticky; top: 0; z-index: 200;
  background: var(--surface);
  border-bottom: 1px solid #eaecf0;
}

/* The header shares the page's measure. It used to need a wider one of its
   own — eight menu entries, the brand and two actions did not fit inside
   1200px — but the page container is wider than that override now, and a
   header narrower than the content it sits above reads as a mistake. */

.header-inner {
  height: var(--header-h);
  display: flex; align-items: center; gap: 16px;
}
.brand { display: flex; align-items: center; gap: 10px; font-weight: 700; color: var(--text); flex: 0 0 auto; }
.brand:hover { text-decoration: none; color: var(--text); }
.brand img { width: 34px; height: 34px; object-fit: contain; border-radius: 8px; }
.brand-mark {
  width: 34px; height: 34px; border-radius: 9px; flex: 0 0 auto;
  display: grid; place-items: center;
  background: linear-gradient(135deg, var(--primary), var(--secondary));
  color: #fff; font-weight: 800; font-size: 15px; font-family: var(--font-num);
}
.brand-text { display: flex; flex-direction: column; line-height: 1.15; }
.brand-text b { font-size: 16px; letter-spacing: -.01em; }
.brand-text span { font-size: 11px; font-weight: 500; color: var(--text-muted); }

.main-nav {
  display: flex; align-items: center; justify-content: center;
  gap: 2px; margin-left: 4px; flex: 1 1 auto; flex-wrap: nowrap;
}
.main-nav a {
  padding: 9px 11px; border-radius: 8px;
  font-size: 13.5px; font-weight: 500; color: #475467;
  white-space: nowrap;
  transition: background var(--t-fast), color var(--t-fast);
}
.main-nav a:hover { background: #f8fafc; color: #155eef; text-decoration: none; }
.main-nav a.active { color: #155eef; background: #eef4ff; font-weight: 600; }

.header-actions { display: flex; align-items: center; gap: 10px; margin-left: auto; flex: 0 0 auto; }
/* The membership call to action, sized for a white header: gold enough to be
   the one thing the eye lands on, flat enough not to shout. */
.header-cta-vip {
  --btn-fg: #fff; --btn-border: #f5a000;
  height: 42px; padding: 0 19px; border-radius: 10px;
  font-size: 14px; font-weight: 700;
  background: #f5a000;
  box-shadow: 0 6px 16px rgba(245, 158, 11, .2);
}
.header-cta-vip:hover {
  color: #fff; background: #e79000; border-color: #e79000;
  box-shadow: 0 6px 16px rgba(231, 144, 0, .24); filter: none; transform: none;
}
.header-cta-vip::after { display: none; }
.header-cta-vip .icon { color: #fff; }
.header-login { height: 40px; padding-inline: 12px; color: #475467; font-weight: 600; }
.header-login:hover { color: #155eef; }
.header-vip-status {
  min-height: 32px; padding: 4px 10px;
  background: #fff8e8; border-color: #f4d69a; color: #a85a05;
}
a.header-vip-status { cursor: pointer; transition: background var(--t-fast), border-color var(--t-fast); }
a.header-vip-status:hover { background: #fdeec6; border-color: #e6bd6b; color: #8a4903; text-decoration: none; }
.header-vip-days { font-variant-numeric: tabular-nums; opacity: .82; font-weight: 600; }
/* The header is tight on a phone: the crown and the word VIP carry the
   meaning, so the day count is the part that gives way first. */
@media (max-width: 560px) { .header-vip-days { display: none; } }
:root[data-theme="dark"] .site-header { border-bottom-color: var(--border); }
:root[data-theme="dark"] .main-nav a { color: var(--text-muted); }
:root[data-theme="dark"] .main-nav a:hover { background: var(--surface-hover); color: var(--primary); }
:root[data-theme="dark"] .main-nav a.active { background: var(--primary-soft); color: var(--primary); }
:root[data-theme="dark"] .header-login { color: var(--text-muted); }
:root[data-theme="dark"] .header-login:hover { color: var(--primary); }
:root[data-theme="dark"] .header-vip-status {
  background: var(--vip-soft); border-color: var(--vip-border); color: var(--vip-strong);
}

.nav-toggle { display: none; }

/* Light / dark switch. One button that swaps the theme; the icon shows the
   palette it will move to, so the reader can predict the result before the
   click. Both icons are in the markup and CSS picks the live one, which keeps
   the button from flickering while a script decides. */
/* .icon-btn is the same control as a link rather than a button — the header's
   search shortcut uses it, so the two sit as a matched pair. */
.theme-toggle, .icon-btn {
  display: inline-grid; place-items: center; flex: 0 0 auto;
  width: 38px; height: 38px; padding: 0;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill); color: var(--text-muted); cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
.theme-toggle:hover, .icon-btn:hover { background: var(--surface-hover); color: var(--text); text-decoration: none; }
.theme-toggle:focus-visible, .icon-btn:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 2px; }
.theme-toggle .icon { grid-area: 1 / 1; }
/* Light page → offer dark (moon). Dark page → offer light (sun). */
.theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: none; }

/* The sign-in link that lives inside the mobile menu. The header shows its own
   copy on wider screens, so this one only appears once the header runs out of
   room for two actions. */
.nav-auth-link { display: none; }

/* Account menu */
.account { position: relative; }
.account-btn {
  display: flex; align-items: center; gap: 8px; padding: 5px 10px 5px 5px;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill); cursor: pointer; font-family: inherit;
  font-size: 14px; font-weight: 600; color: var(--text);
}
.account-btn:hover { background: var(--surface-hover); }
.avatar {
  width: 30px; height: 30px; border-radius: 50%; flex: 0 0 auto;
  display: grid; place-items: center; object-fit: cover;
  background: var(--primary-soft); color: var(--primary-dark);
  font-weight: 700; font-size: 13px; font-family: var(--font-num);
}
.avatar-lg { width: 68px; height: 68px; font-size: 26px; }
/* No photo — or a photo whose URL turned out to be dead, which main.js swaps
   for this. The icon is sized from the circle so one rule covers every size. */
.avatar-empty { color: var(--primary); background: var(--primary-soft); }
.avatar-empty .icon { width: 58%; height: 58%; }
.account-name { max-width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.dropdown {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 210;
  min-width: 220px; padding: 6px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
}
.dropdown[hidden] { display: none; }
.dropdown a, .dropdown button {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 9px 11px; border-radius: var(--radius-xs);
  font-family: inherit; font-size: 14.5px; color: var(--text);
  background: none; border: 0; cursor: pointer; text-align: left;
}
.dropdown a:hover, .dropdown button:hover { background: var(--surface-hover); text-decoration: none; }
.dropdown .sep { height: 1px; background: var(--border); margin: 5px 0; }
.dropdown .head { padding: 9px 11px 7px; border-bottom: 1px solid var(--border); margin-bottom: 5px; }
.dropdown .head b { display: block; font-size: 14.5px; }
.dropdown .head span { font-size: 12.5px; color: var(--text-muted); }
/* Anything about membership, wherever it appears in a menu or a summary. */
.is-vip { display: inline-flex; align-items: center; gap: 5px; color: var(--vip); font-weight: 700; }
.dropdown a.is-vip { display: flex; }
.dropdown a.is-vip:hover { background: var(--vip-soft); color: var(--vip-strong); }
.dropdown .head span.is-vip { margin-top: 3px; }

/* ------------------------------------------------------- Notification bell
   The bell reuses .account for positioning and .dropdown for the panel, so it
   inherits the existing open/close behaviour and click-away handling. What is
   added here is the count, the row and the four status tones. */
.notif-btn {
  position: relative; display: grid; place-items: center;
  width: 38px; height: 38px; flex: 0 0 auto;
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: 50%; color: var(--text-muted); cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
.notif-btn:hover { background: var(--surface-hover); color: var(--primary); border-color: var(--primary-border); }
.notif-btn[aria-expanded="true"] { background: var(--primary-soft); color: var(--primary); border-color: var(--primary-border); }

/* The count sits on the rim, not inside: at two digits it would crowd the
   glyph, and it must read as a badge on the control rather than as its label. */
.notif-count {
  position: absolute; top: -3px; right: -3px;
  min-width: 18px; height: 18px; padding: 0 5px;
  display: grid; place-items: center;
  background: var(--danger); color: #fff;
  border: 2px solid var(--surface); border-radius: var(--radius-pill);
  font: 700 10.5px/1 var(--font-num);
}

.notif-panel { width: min(360px, calc(100vw - 32px)); padding: 0; overflow: hidden; }
.notif-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 12px 14px; border-bottom: 1px solid var(--border);
}
.notif-head b { font-size: 14.5px; }
.notif-panel .notif-readall {
  width: auto; padding: 4px 8px; border-radius: var(--radius-xs);
  font-size: 12.5px; font-weight: 600; color: var(--primary);
}
.notif-panel .notif-readall:hover { background: var(--primary-soft); }

/* Eight rows is about a screen on a phone; past that the panel scrolls rather
   than growing past the viewport. */
.notif-list { max-height: min(60vh, 420px); overflow-y: auto; }

.notif-panel .notif-item {
  display: flex; align-items: flex-start; gap: 10px;
  width: 100%; padding: 11px 14px; border-radius: 0;
  border-bottom: 1px solid var(--border);
}
.notif-panel .notif-item:last-of-type { border-bottom: 0; }
/* Unread rows carry a tint and a dot. Read rows are plain, which is what makes
   "what is new" answerable without reading a single word. */
.notif-panel .notif-item.is-unread { background: var(--primary-soft); }
.notif-panel .notif-item.is-unread:hover { background: var(--primary-soft-2); }

.notif-item-icon {
  width: 30px; height: 30px; flex: 0 0 auto; display: grid; place-items: center;
  border-radius: 50%; margin-top: 1px;
}
.notif-item-icon.tone-info    { color: var(--primary); background: var(--primary-soft); }
.notif-item-icon.tone-pending { color: var(--warning); background: var(--warning-soft); }
.notif-item-icon.tone-success { color: var(--success); background: var(--success-soft); }
.notif-item-icon.tone-danger  { color: var(--danger);  background: var(--danger-soft); }

.notif-item-body { display: grid; gap: 2px; min-width: 0; flex: 1 1 auto; }
.notif-item-title { font-size: 13.5px; font-weight: 700; line-height: 1.4; }
.notif-item-msg {
  color: var(--text-muted); font-size: 12.5px; line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.notif-item-time { color: var(--text-subtle); font-size: 11.5px; margin-top: 1px; }
.notif-item-dot {
  width: 7px; height: 7px; flex: 0 0 auto; margin-top: 12px;
  background: var(--primary); border-radius: 50%;
}

.notif-empty { padding: 26px 16px; text-align: center; color: var(--text-muted); }
.notif-empty-icon {
  display: grid; place-items: center; width: 44px; height: 44px; margin: 0 auto 9px;
  border-radius: 50%; color: var(--text-subtle); background: var(--surface-muted);
}
.notif-empty p { margin: 0; font-size: 13.5px; }

.notif-panel .notif-all {
  justify-content: center; border-top: 1px solid var(--border); border-radius: 0;
  padding: 11px; font-size: 13.5px; font-weight: 600; color: var(--primary);
}
.notif-panel .notif-all:hover { background: var(--primary-soft); }

/* The panel is anchored to the bell, which sits near the right edge on a
   phone; without this it would hang off the screen. */
@media (max-width: 575px) {
  .notif-btn { width: 36px; height: 36px; }
  .notif-panel { position: fixed; right: 12px; left: 12px; width: auto; top: calc(var(--header-h) + 6px); }
}

/* One page of the whole feed, /member/notifications.php. Same row as the
   panel, given room to breathe. */
.notif-page { display: grid; }
.notif-page .notif-item {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 14px var(--space); border-bottom: 1px solid var(--border); color: var(--text);
}
.notif-page .notif-item:last-child { border-bottom: 0; }
.notif-page .notif-item:hover { background: var(--surface-hover); text-decoration: none; }
.notif-page .notif-item.is-unread { background: var(--primary-soft); }
.notif-page .notif-item.is-unread:hover { background: var(--primary-soft-2); }
.notif-page .notif-item-title { font-size: 14.5px; }
.notif-page .notif-item-msg { font-size: 13px; -webkit-line-clamp: 3; }

/* --------------------------------------------------------- Device sessions
   Two screens share one row: the gate a third device lands on, and the list in
   the member's own account. The row is a flex line rather than a table, so the
   phone layout is the same layout with the button wrapped underneath — not a
   desktop table squeezed into 375px. */
.device-gate {
  max-width: 560px; margin: 0 auto; padding: clamp(22px, 4vw, 34px);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); text-align: center;
}
.device-gate-mark {
  width: 56px; height: 56px; display: grid; place-items: center; margin: 0 auto 14px;
  border-radius: 50%; color: var(--warning); background: var(--warning-soft);
}
.device-gate h1 { font-size: clamp(21px, 3.4vw, 27px); margin: 0 0 8px; letter-spacing: -.02em; }
.device-gate .lead { color: var(--text-muted); font-size: 14.5px; line-height: 1.7; margin: 0 0 20px; }
.device-gate-note {
  display: flex; align-items: flex-start; gap: 7px; justify-content: center;
  margin: 14px 0 0; color: var(--text-subtle); font-size: 12.5px; line-height: 1.6; text-align: left;
}
.device-gate-note .icon { flex: 0 0 auto; margin-top: 2px; color: var(--warning); }
.device-gate-foot { margin-top: 16px; font-size: 13.5px; }

.device-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; text-align: left; }
.device-row {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 14px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface);
}
.device-row-icon {
  width: 38px; height: 38px; flex: 0 0 auto; display: grid; place-items: center;
  border-radius: 50%; color: var(--primary); background: var(--primary-soft);
}
.device-row-body { flex: 1 1 200px; min-width: 0; display: grid; gap: 2px; }
.device-row-body b { font-size: 14.5px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.device-row-body span { color: var(--text-muted); font-size: 12.5px; line-height: 1.5; }
.device-row-meta { color: var(--text-subtle) !important; }
.device-row-action { margin: 0; flex: 0 0 auto; }

/* The machine the reader is on says so, in the brand's colour rather than in a
   second sentence they have to match up with the list. */
.device-badge {
  padding: 2px 8px; border-radius: var(--radius-pill);
  background: var(--primary-soft); color: var(--primary-dark);
  font-size: 11px; font-weight: 700;
}
.device-row.is-current { border-color: var(--primary-border); background: var(--primary-soft); }

/* Inside a card on the profile page the rows are a divided list, not a stack
   of boxes: the card already provides the border. */
.device-list-page { gap: 0; }
.device-list-page .device-row {
  border: 0; border-bottom: 1px solid var(--border); border-radius: 0; background: none;
}
.device-list-page .device-row:last-child { border-bottom: 0; }
.device-list-page .device-row.is-current { background: var(--primary-soft); }

.device-summary {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space); flex-wrap: wrap; margin-bottom: var(--space);
}
.device-summary-count { display: block; font-size: 26px; font-weight: 800; color: var(--primary-dark); line-height: 1.2; }
.device-summary-label { color: var(--text-muted); font-size: 13px; }
.device-summary p { margin: 0; flex: 1 1 260px; color: var(--text-muted); font-size: 12.5px; line-height: 1.6; }

.device-bulk { margin-top: var(--space); }
.device-bulk-note { margin: 8px 0 0; color: var(--text-subtle); font-size: 12.5px; text-align: center; }

@media (max-width: 575px) {
  .device-row { align-items: flex-start; }
  .device-row-action { width: 100%; }
  .device-row-action .btn { width: 100%; justify-content: center; }
  .device-summary { text-align: left; }
}

/* The footer is the one full-width navy surface every page ends on. A white
   footer on a white page gave the site no close at all — it just ran out of
   content. This gives every page a deliberate bottom edge. */
.site-footer {
  position: relative; overflow: hidden;
  background:
    radial-gradient(900px 400px at 12% -30%, rgba(43, 88, 232, .3), transparent 62%),
    radial-gradient(700px 360px at 92% 130%, rgba(14, 165, 233, .16), transparent 60%),
    var(--navy);
  color: var(--navy-fg);
  /* Compact on purpose. The footer is the page's bottom edge, not a section of
     its own — at 84px top and bottom it was taller than the article strip
     above it and the page ended on a field of navy. */
  padding: 44px 0 20px;
  margin-top: var(--space-xl);
}
/* A thin brand rule where the page meets the footer. */
.site-footer::before {
  content: ''; position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--primary) 22%, var(--secondary) 55%, var(--vip) 78%, transparent);
  opacity: .8;
}
.site-footer .brand,
.site-footer .brand:hover { color: #fff; }
.site-footer .brand-text span { color: var(--navy-dim); }
.site-footer .text-muted { color: var(--navy-dim); }
.site-footer .btn-outline {
  --btn-bg: rgba(255, 255, 255, .05); --btn-fg: #e6ecfa; --btn-border: var(--navy-line);
}
.site-footer .btn-outline:hover { --btn-bg: rgba(255, 255, 255, .11); color: #fff; }
/* Brand block, then three link columns. The template used to be
   `1.6fr repeat(auto-fit, …)`, which CSS rejects — an automatic repeat cannot
   sit beside a flexible track — so the whole declaration was dropped and the
   footer stacked into one column on every screen. */
.footer-grid {
  display: grid; grid-template-columns: 1.9fr repeat(3, minmax(130px, 1fr));
  gap: var(--space-md); margin-bottom: var(--space);
}
.footer-grid h4 {
  font-size: 11.5px; margin-bottom: 12px; color: #fff;
  letter-spacing: .1em; text-transform: uppercase; font-weight: 700;
}
.footer-grid ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.footer-grid a { font-size: 13.5px; color: var(--navy-fg); }
/* Visitor stats bar in footer */
.footer-stats {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 14px;
  padding: 5px 13px;
  background: rgba(255, 255, 255, .04);
  border: 1px solid rgba(255, 255, 255, .08);
  border-radius: 999px;
  font-size: 12.5px;
  color: var(--navy-dim, #94a3b8);
  line-height: 1.4;
}
.footer-stats-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.footer-stats-text {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
}
.footer-stats-icon {
  display: inline-flex;
  align-items: center;
  color: #7dd3fc;
  line-height: 1;
}
.footer-stats-icon svg {
  display: block;
}
.footer-stats-online-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background-color: #22c55e;
  display: inline-block;
  flex-shrink: 0;
}
.footer-stats-num {
  color: #ffffff;
  font-weight: 700;
  font-family: var(--font-num, system-ui);
  letter-spacing: .02em;
}
.footer-stats-label {
  color: var(--navy-dim, #94a3b8);
  font-size: 12px;
}
.footer-stats-sep {
  color: rgba(255, 255, 255, .2);
  font-size: 10px;
  line-height: 1;
  user-select: none;
}

/* The announcement strip. It sits above the header rather than under it, so it
   never covers the navigation, and it is only in the document at all when an
   administrator has switched it on and written a line — see
   site_announcement(). One brand-coloured band, no close button: a strip that
   can be dismissed is a strip that stops being read after the first visit, and
   the way to remove it is to turn it off. */
.announce {
  background: var(--primary); color: #fff;
  font-size: 13.5px; font-weight: 500; line-height: 1.45;
}
.announce .container {
  display: flex; justify-content: center; align-items: center;
  min-height: 40px; padding-block: 8px; text-align: center;
}
.announce a, .announce > .container > span {
  display: inline-flex; align-items: center; gap: 8px; color: #fff;
}
.announce a:hover { color: #fff; text-decoration: underline; }
.announce .icon { flex: 0 0 auto; }

/* Social marks. Round, unlabelled and the size of a touch target. */
.footer-social { display: flex; gap: 9px; margin-top: 14px; }
.footer-social a {
  width: 36px; height: 36px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(255, 255, 255, .07); border: 1px solid var(--navy-line);
  color: #e6ecfa;
  transition: background var(--t-fast), color var(--t-fast), transform var(--t-fast);
}
.footer-social a:hover { background: var(--primary); color: #fff; transform: translateY(-2px); }
/* The link slides a little on hover instead of only changing colour. */
.footer-grid a {
  display: inline-block; transition: color var(--t-fast), transform var(--t-fast);
}
.footer-grid a:hover { color: #fff; text-decoration: none; transform: translateX(3px); }
.footer-bottom {
  border-top: 1px solid var(--navy-line); padding-top: 16px; margin-top: var(--space-md);
  display: flex; justify-content: space-between; gap: var(--space-sm);
  flex-wrap: wrap; font-size: 12.5px; color: var(--navy-dim);
}

/* ------------------------------------------------------------- 10. HOME PAGE */
/* The hero. Two very soft light sources over a near-white canvas: at this
   strength the background reads as paper catching light rather than as a
   coloured band, which is what keeps a landing page from looking like a
   dashboard header. The grid pattern that used to sit on top of it is gone —
   it was the most visible thing in the first screen and it carried nothing. */
.hero {
  position: relative;
  overflow: hidden;
  padding: 36px 0 24px;
}

.hero + .section-tight,
.section-figures + .section-tight { padding-top: 4px; }

/* The full-width hero card container matching Reference Image 1 */
.hero-card {
  position: relative;
  border-radius: 28px;
  border: 1px solid color-mix(in srgb, var(--primary) 12%, var(--border));
  background: #eef7ff url('../img/home-hero-background-v2.webp') center center / cover no-repeat;
  box-shadow: 0 16px 40px -12px rgba(28, 71, 204, 0.08), 0 2px 8px rgba(15, 23, 42, 0.04);
  padding: 38px 44px 32px;
  overflow: hidden;
  isolation: isolate;
}

:root[data-theme="dark"] .hero-card {
  border-color: rgba(255, 255, 255, 0.09);
  background: #0f1c3f url('../img/home-hero-background-v2.webp') center center / cover no-repeat;
  box-shadow: 0 16px 40px -12px rgba(0, 0, 0, 0.45);
}

/* Background Decorative Layers */
.hero-card-decor {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 0;
  overflow: hidden;
}

.hero-decor-svg {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* 2-Column Grid Layout: 50% / 50% */
.hero-card-grid {
  position: relative;
  z-index: 1;
  display: block;
}

/* LEFT COLUMN: Content */
.hero-card-content {
  width: 52%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* Eyebrow Badge */
.hero-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 17px 7px 13px;
  border-radius: 999px;
  background: #e0f2fe;
  border: 1px solid #bae6fd;
  color: #0284c7;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.4;
  margin-bottom: 10px;
}

.hero-badge-ic {
  display: inline-flex;
  align-items: center;
  color: #0284c7;
}

:root[data-theme="dark"] .hero-badge {
  background: rgba(14, 165, 233, 0.15);
  border-color: rgba(56, 189, 248, 0.3);
  color: #38bdf8;
}
:root[data-theme="dark"] .hero-badge-ic {
  color: #38bdf8;
}

/* Main Headline */
.hero-title {
  margin: 0 0 10px;
  font-size: clamp(34px, 3.4vw, 45px);
  line-height: 1.22;
  letter-spacing: -0.025em;
}

.hero-title-main {
  display: block;
  color: #0a1430;
  font-size: 0.98em;
  font-weight: 800;
  line-height: 1.08;
}

:root[data-theme="dark"] .hero-title-main {
  color: #f8fafc;
}

.hero-title-accent {
  display: inline-block;
  position: relative;
  color: #1c47cc;
  font-size: 1.4em;
  font-weight: 800;
  line-height: 1.04;
}

:root[data-theme="dark"] .hero-title-accent {
  color: #60a5fa;
}

.hero-title-brush {
  position: absolute;
  left: 0;
  bottom: -6px;
  width: 100%;
  height: 8px;
  pointer-events: none;
}

/* Description */
.hero-description {
  font-size: clamp(14.5px, 1.3vw, 15.5px);
  line-height: 1.65;
  color: #64748b;
  font-weight: 450;
  margin: 0 0 18px;
  max-width: 50ch;
}

:root[data-theme="dark"] .hero-description {
  color: #94a3b8;
}

/* 3 CTA Buttons */
.hero-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 26px;
}

.hero-actions-secondary {
  display: flex;
  align-items: center;
  gap: 12px;
}

.hero-btn-main {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  height: 54px;
  padding: 0 22px 0 15px;
  border-radius: 14px;
  background: linear-gradient(145deg, #2563eb 0%, #1d4ed8 50%, #1e40af 100%);
  color: #ffffff !important;
  font-size: 16px;
  font-weight: 700;
  text-decoration: none;
  box-shadow: 0 10px 24px -4px rgba(37, 99, 235, 0.42), 0 3px 8px -2px rgba(37, 99, 235, 0.25);
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.2s ease;
  white-space: nowrap;
}

.hero-btn-main:hover {
  transform: translateY(-2px);
  box-shadow: 0 14px 28px -4px rgba(37, 99, 235, 0.55), 0 6px 12px -2px rgba(37, 99, 235, 0.35);
}

.hero-btn-main:active {
  transform: translateY(0);
}

.hero-btn-play {
  width: auto;
  height: auto;
  border-radius: 0;
  background: transparent;
  color: #ffffff;
  display: grid;
  place-items: center;
  padding: 0;
  box-shadow: none;
  flex-shrink: 0;
}

.hero-btn-play .icon {
  fill: currentColor !important;
  stroke: none !important;
  width: 13px;
  height: 13px;
}

.hero-btn-sub {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  height: 54px;
  padding: 0 17px;
  border-radius: 14px;
  background: #ffffff;
  border: 1.5px solid #e2e8f0;
  color: #1e293b !important;
  font-size: 15.5px;
  font-weight: 600;
  text-decoration: none;
  box-shadow: 0 2px 6px rgba(15, 23, 42, 0.04);
  transition: all 0.2s ease;
  white-space: nowrap;
}

.hero-btn-sub:hover {
  background: #f8fafc;
  border-color: #cbd5e1;
  color: #0f172a !important;
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(15, 23, 42, 0.06);
}

.hero-btn-sub:active {
  transform: translateY(0);
}

.hero-btn-sub-ic {
  display: inline-flex;
  align-items: center;
  color: #2563eb;
  flex-shrink: 0;
}

:root[data-theme="dark"] .hero-btn-sub {
  background: #1e293b;
  border-color: #334155;
  color: #f1f5f9 !important;
  box-shadow: none;
}
:root[data-theme="dark"] .hero-btn-sub:hover {
  background: #334155;
  border-color: #475569;
}
:root[data-theme="dark"] .hero-btn-sub-ic {
  color: #60a5fa;
}

/* Feature Highlights Under CTA */
.hero-features {
  display: flex;
  align-items: center;
  gap: 0;
  width: 100%;
}

.hero-feat-item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 0 18px;
  border-right: 1.5px solid rgba(203, 213, 225, 0.7);
  color: #334155;
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
}

.hero-feat-item:first-child {
  padding-left: 0;
}

.hero-feat-item:last-child {
  border-right: none;
  padding-right: 0;
}

.hero-feat-ic {
  display: inline-flex;
  align-items: center;
  color: #2563eb;
  flex-shrink: 0;
}

:root[data-theme="dark"] .hero-feat-item {
  color: #cbd5e1;
  border-color: rgba(255, 255, 255, 0.1);
}
:root[data-theme="dark"] .hero-feat-ic {
  color: #60a5fa;
}

/* RIGHT COLUMN: Visual Mascot */
.hero-card-visual {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  min-width: 0;
  z-index: 1;
}

.hero-mascot-wrap {
  position: relative;
  width: 116%;
  max-width: 620px;
  display: flex;
  justify-content: center;
  align-items: center;
  transform: translateX(-5%);
  animation: hero-mascot-float 6.5s ease-in-out infinite alternate;
}

@keyframes hero-mascot-float {
  0%   { transform: translate(-5%, 0); }
  100% { transform: translate(-5%, -8px); }
}

.hero-mascot-glow {
  position: absolute;
  width: 380px;
  height: 380px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(59, 130, 246, 0.14) 0%, rgba(14, 165, 233, 0.05) 55%, transparent 72%);
  pointer-events: none;
  z-index: 0;
}

.hero-mascot-orbit {
  position: absolute;
  width: 440px;
  height: 180px;
  border-radius: 50%;
  border: 2px solid rgba(56, 189, 248, 0.28);
  transform: rotate(-10deg);
  pointer-events: none;
  z-index: 0;
}

.hero-mascot-img {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 620px;
  height: auto;
  aspect-ratio: 1024 / 682;
  display: block;
  filter: drop-shadow(0 14px 28px rgba(15, 23, 42, 0.07));
  pointer-events: none;
  user-select: none;
}

/* The figures under the hero. Four separate cards on their own band rather
   than one divided bar: they are the page's only outside evidence that the
   site is used, and at bar scale they read as small print under the copy. */
.section-figures { padding: 4px 0 var(--space-md); }
.stat-grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 20px;
}
/* The icon leads and the figure sits beside it, so the row reads left to
   right: what is being counted, then how many. */
.stat-card {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: auto auto; column-gap: 14px;
  align-content: center; align-items: center;
  padding: 18px 20px; min-width: 0;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: 0 4px 14px rgba(15, 23, 42, .05);
  transition: transform var(--t), box-shadow var(--t), border-color var(--t);
}
.stat-card:hover {
  transform: translateY(-3px);
  border-color: var(--primary-border);
  box-shadow: 0 12px 30px rgba(15, 23, 42, .08);
}
.stat-card .ic {
  grid-row: 1 / 3; width: 44px; height: 44px; border-radius: 12px;
  display: grid; place-items: center;
  background: var(--primary-soft); color: var(--primary);
}
.stat-card b {
  font-family: var(--font-num); font-size: 23px; font-weight: 800;
  color: var(--text); letter-spacing: -.025em; line-height: 1.2;
}
.stat-card > span:last-child { font-size: 12.5px; color: var(--text-muted); line-height: 1.35; }
/* A rotation of four tints so the row has some life without becoming a set of
   unrelated coloured boxes — the same rotation the category tiles use. */
.stat-grid > :nth-child(2) .ic { background: var(--success-soft); color: var(--success); }
.stat-grid > :nth-child(3) .ic { background: var(--vip-soft); color: var(--vip); }
.stat-grid > :nth-child(4) .ic { background: color-mix(in srgb, #a855f7 12%, var(--surface)); color: #8b3ff0; }
:root[data-theme="dark"] .stat-grid > :nth-child(4) .ic { background: #2a1b46; color: #c4a2ff; }

/* The hero visual is a real screenshot-like preview of the exam interface —
   it shows the product rather than a generic illustration. */
/* The product preview floats above the hero: a deep shadow, a hairline that
   catches brand colour along its top edge, and a slow idle float so the panel
   reads as suspended rather than pasted on. */
.hero-visual {
  position: relative;
  background: var(--surface-raised); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: 0 12px 32px rgba(15, 23, 42, .08);
  padding: 20px; overflow: hidden;
  animation: hero-float 7s ease-in-out infinite alternate;
}
.hero-visual::before {
  content: ''; position: absolute; left: 12%; right: 12%; top: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--primary), var(--secondary), transparent);
  opacity: .75;
}
@keyframes hero-float {
  from { transform: translateY(0); }
  to   { transform: translateY(-10px); }
}
.hero-visual img { border-radius: var(--radius); display: block; }
/* The card's own header: what this is on the left, where the reader stands and
   how long they have on the right. The clock is the one amber thing in the
   first screen, which is exactly the weight a timer should carry. */
.hv-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding-bottom: 11px; margin-bottom: 12px; border-bottom: 1px solid var(--border);
}
.hv-head > b { font-size: 15px; letter-spacing: -.01em; }
.hv-meta { display: inline-flex; align-items: center; gap: 8px; }
.hv-count {
  padding: 4px 11px; border-radius: var(--radius-pill);
  background: var(--primary-soft); color: var(--primary-dark);
  font-size: 12px; font-weight: 700; font-family: var(--font-num);
}
.hv-timer {
  display: inline-flex; align-items: center; gap: 5px; padding: 4px 11px;
  background: var(--warning-soft); color: var(--warning);
  border-radius: var(--radius-pill); font-size: 12px; font-weight: 700; font-family: var(--font-num);
}
.hv-q { font-size: 15px; font-weight: 600; margin-bottom: 12px; line-height: 1.55; }
.hv-choice {
  display: flex; align-items: center; gap: 11px; padding: 9px 14px; margin-bottom: 8px;
  min-height: 42px;
  border: 1px solid var(--border); border-radius: var(--radius-sm); font-size: 14px;
  background: var(--surface);
  transition: border-color var(--t-fast), background var(--t-fast);
}
.hv-choice:hover { border-color: var(--primary-border); }
/* An empty radio, the way the runner draws an unpicked answer — the letter
   sits in the label itself, so the control is only ever the state. */
.hv-choice .k {
  width: 18px; height: 18px; flex: 0 0 auto; border-radius: 50%;
  border: 2px solid var(--border-strong); background: var(--surface);
}
.hv-choice .mark {
  margin-left: auto; width: 20px; height: 20px; flex: 0 0 auto; border-radius: 50%;
  display: grid; place-items: center; background: var(--success); color: #fff;
}
.hv-choice.correct { border-color: var(--success-border); background: var(--success-soft); color: var(--success); }
.hv-choice.correct .k { border-color: var(--success); box-shadow: inset 0 0 0 3px var(--success-soft), inset 0 0 0 9px var(--success); }
/* The line the reader sees the moment they answer. The preview stops at "you
   got it, here is why" because that is the whole product promise, and a still
   picture of the runner without it only shows half of what happens. */
.hv-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; flex-wrap: wrap;
  margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--border);
}
.hv-foot .ok {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 13.5px; font-weight: 700; color: var(--success);
}
/* The explanation is the product's actual promise, so it gets a control's
   shape — but an outline one, because the page's real call to action is the
   button on the other side of the hero. */
.hv-foot .explain-chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 7px 14px;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface); font-size: 12.5px; font-weight: 600; color: var(--text-muted);
  transition: border-color var(--t-fast), color var(--t-fast);
}
.hero-visual:hover .hv-foot .explain-chip { border-color: var(--primary-border); color: var(--primary); }

/* Daily Question feature card on the home page. Deep blue into bright blue —
   the one saturated surface above the footer, because the day's set is the
   single thing this page most wants a visitor to start. */
.daily-card {
  background: linear-gradient(135deg, #1239c5 0%, #0958e8 55%, #0b8ee8 100%);
  border-radius: 16px; color: #fff; padding: 26px;
  box-shadow: 0 16px 32px rgba(21, 94, 239, .18); position: relative; overflow: hidden;
  display: flex; align-items: center;
}
.daily-card::after {
  content: ''; position: absolute; right: -70px; bottom: -90px;
  width: 240px; height: 240px; border-radius: 50%;
  background: rgba(255, 255, 255, .07);
}
/* The drawing is absolutely placed and the copy is inset past it, rather than
   the two being grid columns: the panel's own padding then still applies to
   both, and the illustration can bleed off the card's edge the way the target
   does without a column of empty space beside it. */
.daily-card .dc-body {
  position: relative; z-index: 1; flex: 1 1 auto; min-width: 0;
  padding-right: 232px;
}
/* The drawing takes about 38% of the panel, which is what makes it read as an
   illustration rather than as an icon parked in the corner. */
.dc-art {
  position: absolute; right: -10px; top: 50%; transform: translateY(-50%);
  width: 262px; height: auto; pointer-events: none;
}
.daily-card .dc-top { display: flex; align-items: center; gap: 8px; font-size: 12.5px; line-height: 1.4; opacity: .9; margin-bottom: 8px; }
.daily-card h3 {
  color: #fff; font-size: 21px; margin-bottom: 13px; position: relative;
  display: flex; align-items: center; gap: 7px;
}
.daily-card .dc-hot { display: inline-flex; color: #fdba74; }
/* A glass panel with its own label: the question inside it is a sample, not
   the card's copy, and the label is what says so. */
.daily-card .dc-q {
  background: rgba(255, 255, 255, .13); border: 1px solid rgba(255, 255, 255, .24);
  border-radius: var(--radius-sm); padding: 11px 14px; font-size: 13.5px; line-height: 1.5;
  margin-bottom: 15px; position: relative;
  display: grid; gap: 3px;
}
.daily-card .dc-q .k {
  font-size: 10.5px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; opacity: .72;
}
.daily-card .dc-facts { display: flex; gap: 34px; flex-wrap: wrap; margin-bottom: 16px; position: relative; }
.daily-card .dc-facts div { font-size: 11.5px; opacity: .85; }
.daily-card .dc-facts b { display: block; font-size: 22px; font-family: var(--font-num); opacity: 1; line-height: 1.25; }
.daily-card .btn-block { height: 46px; font-size: 15px; border-radius: var(--radius-sm); }
.daily-card .dc-note {
  margin: 9px 0 0; font-size: 11.5px; line-height: 1.4; opacity: .82; text-align: center; position: relative;
}
.daily-card .btn { position: relative; }
/* On the blue card the primary action inverts to white. It has to override
   `background`, not just --btn-bg, because .btn-primary paints a gradient. */
.daily-card .btn-primary {
  --btn-fg: var(--primary-dark); --btn-border: #fff;
  background: #fff;
  box-shadow: inset 0 -1px 0 rgba(12, 23, 48, .08), 0 6px 18px -6px rgba(0, 0, 0, .45);
}
.daily-card .btn-primary:hover { background: #eef2ff; color: var(--primary-dark); filter: none; }
/* The sheen would be invisible on white; the amber button beside it keeps its. */
.daily-card .btn-primary::after { display: none; }

/* ---- "Today": where the reader stands, and what to do next ----------------
   Two panels on one row. The left one is the reader — their streak, their
   progress through today's sets, their figures — or, for a visitor who has no
   record yet, the day's set itself. The right one is the short list of what to
   do next, which is the only thing a returning reader actually came for. */
.today-grid {
  display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: 22px; align-items: stretch;
}
.today-card { padding: var(--space-md); display: flex; flex-direction: column; }
.today-who { display: flex; align-items: center; gap: 13px; flex-wrap: wrap; }
.today-who .avatar { width: 48px; height: 48px; font-size: 19px; }
.today-who h2 { font-size: 18px; margin: 0 0 4px; letter-spacing: -.01em; }

.today-progress { margin-top: var(--space-md); }
.today-progress .k {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; font-size: 13px; color: var(--text-muted); margin-bottom: 8px;
}
.today-progress .k b { font-family: var(--font-num); font-size: 15px; color: var(--primary); }

/* Three figures under the bar. An icon, a number and a label on one line each,
   so the set stays a row of facts rather than three more cards. */
.today-mini {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-sm); margin-top: auto;
  padding-top: var(--space); border-top: 1px solid var(--border);
}
.today-mini > div,
.today-mini > a { display: flex; align-items: center; gap: 10px; min-width: 0; color: inherit; text-decoration: none; }
/* Two tiles instead of three, for a free account whose statistics are locked. */
.today-mini-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.today-mini > a:hover .ic { background: var(--vip-soft); color: var(--vip-strong); }
.today-mini > a:hover b { color: var(--vip-strong); }
.today-mini .ic {
  width: 32px; height: 32px; flex: 0 0 auto; border-radius: var(--radius-sm);
  display: grid; place-items: center;
  background: var(--surface-muted); color: var(--text-muted);
}
.today-mini b { display: block; font-family: var(--font-num); font-size: 16.5px; line-height: 1.2; }
.today-mini span { font-size: 12px; color: var(--text-subtle); }

/* Sized to finish level with the challenge panel beside it: a title, three
   rows and a tip, with no spare height between them. */
.plan-today { padding: 22px 24px; display: flex; flex-direction: column; }
.plan-today > h2 { font-size: 20px; line-height: 1.3; margin: 0 0 3px; letter-spacing: -.02em; }
.plan-sub { font-size: 13px; line-height: 1.4; color: var(--text-muted); margin: 0 0 14px; }

/* The three steps. Each row is a bordered card and the whole row is the link,
   so the number, the icon and the copy all point at one destination. */
.step-list { display: grid; gap: 10px; }
.step {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px; min-height: 64px;
  border: 1px solid var(--border); border-radius: 12px;
  background: var(--surface); color: var(--text);
  transition: border-color var(--t-fast), background var(--t-fast), transform var(--t-fast), box-shadow var(--t-fast);
}
.step:hover {
  text-decoration: none; color: var(--text);
  border-color: var(--primary-border); background: var(--surface-hover);
  transform: translateX(2px); box-shadow: var(--shadow-xs);
}
.step .n {
  width: 26px; height: 26px; flex: 0 0 auto; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--primary); color: var(--primary-contrast);
  font-size: 13px; font-weight: 700; line-height: 1;
}
.step .ic {
  width: 34px; height: 34px; flex: 0 0 auto; border-radius: var(--radius-sm);
  display: grid; place-items: center;
  background: var(--primary-soft); color: var(--primary);
}
.step .ic.tone-vip     { background: var(--vip-soft);     color: var(--vip); }
.step .ic.tone-success { background: var(--success-soft);  color: var(--success); }
.step .body { flex: 1 1 auto; min-width: 0; }
.step .body b { display: block; font-size: 14px; line-height: 1.4; }
.step .body span { display: block; font-size: 11.5px; color: var(--text-muted); line-height: 1.45; }
.step .go { flex: 0 0 auto; color: var(--text-subtle); display: inline-flex; }
.step:hover .go { color: var(--primary); }

/* The panel's closing note: the habit the whole page is arguing for. */
.plan-foot { margin-top: auto; padding-top: 14px; }
.plan-more {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13.5px; font-weight: 600; color: var(--primary);
}
.plan-tip {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 9px 12px; margin: 0;
  background: var(--warning-soft); border: 1px solid var(--warning-border);
  border-radius: var(--radius-sm);
  font-size: 11.5px; line-height: 1.5; color: var(--text);
}
.plan-tip .icon { color: var(--warning); margin-top: 1px; }
.plan-tip b { color: var(--warning); }

/* One thing to do. Hairlines between rows rather than a card each: three
   stacked cards inside a card is exactly the pile-up this list avoids. */
.task { display: flex; align-items: center; gap: 11px; padding: 7px 0; }
.task + .task { border-top: 1px solid var(--border); }
.task:last-child { padding-bottom: 0; }
.task .ic {
  width: 32px; height: 32px; flex: 0 0 auto; border-radius: var(--radius-sm);
  display: grid; place-items: center;
  background: var(--primary-soft); color: var(--primary);
}
.task .ic.tone-vip     { background: var(--vip-soft);     color: var(--vip); }
.task .ic.tone-warning { background: var(--warning-soft); color: var(--warning); }
.task .ic.tone-success { background: var(--success-soft);  color: var(--success); }
.task .body { flex: 1 1 auto; min-width: 0; }
.task .body b { display: block; font-size: 13.5px; line-height: 1.4; }
/* Block, not inline: an inline span's line box is measured against the
   parent's 1.7 strut, so at 11.5px it still claimed 26px of height and every
   row in the panel was 9px taller than its own content. */
.task .body span { display: block; font-size: 11.5px; color: var(--text-muted); line-height: 1.45; }
.task > .btn { flex: 0 0 auto; }
/* The action on a task row labels the row; it is never the page's main call to
   action, so it stays the smallest control on the panel. */
.plan-today .task > .btn { height: 30px; padding: 0 12px; font-size: 12.5px; }

/* Category tile. Centred and vertical: seven of them sit on one row, and at
   that width a name beside an icon wraps to three lines while a name under one
   does not. */
.cat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(146px, 1fr)); gap: 12px; }
.cat-tile {
  padding: var(--space) 12px 13px;
  align-items: center; text-align: center;
}
.cat-icon {
  width: 44px; height: 44px; flex: 0 0 auto; border-radius: var(--radius);
  display: grid; place-items: center;
  background: var(--primary-soft); color: var(--primary);
}
.cat-tile .cat-icon { border-radius: 50%; margin-bottom: 11px; }
.cat-tile h3 { font-size: 14.5px; margin: 0 0 3px; line-height: 1.4; }
.cat-tile .meta { font-size: 12.5px; color: var(--text-muted); }
.cat-tile .go-arrow { margin-top: 11px; color: var(--text-subtle); }
.cat-grid > :nth-child(4n+2) .cat-icon { background: var(--secondary-soft); color: var(--secondary); }
.cat-grid > :nth-child(4n+3) .cat-icon { background: var(--vip-soft);       color: var(--vip); }
.cat-grid > :nth-child(4n+4) .cat-icon { background: var(--success-soft);   color: var(--success); }

/* One subject's daily set. Its state — untouched, in progress, done — is the
   card's most useful fact, so it is carried on the border as well as in the
   badge rather than by colour in one place only. */
.subject-card { display: flex; flex-direction: column; padding: 18px; height: 100%; }
.subject-card.is-done { border-color: var(--success-border); box-shadow: inset 3px 0 0 var(--success); }
.subject-card.is-open { border-color: var(--warning-border); box-shadow: inset 3px 0 0 var(--warning); }
.subject-card .top { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.subject-card .who { display: flex; align-items: center; gap: 9px; min-width: 0; }
.subject-card .who .cat-icon { width: 38px; height: 38px; }
.subject-card .who b { font-size: 15.5px; }
.subject-card h3 { font-size: 15px; font-weight: 600; margin: 0 0 8px; line-height: 1.5; }
.subject-card .facts {
  display: flex; gap: 12px; flex-wrap: wrap;
  font-size: 12.5px; color: var(--text-muted); margin-bottom: 14px;
}
.subject-card .facts span { display: inline-flex; align-items: center; gap: 5px; }
.subject-card .action { margin-top: auto; display: flex; gap: 7px; }
.subject-card .action .btn { flex: 1 1 auto; }

/* ------------------------------------------------ DAILY QUESTION HUB */
/* This page follows the visual rhythm of the supplied Daily Question target
   while keeping every set, attempt state and archive row database-driven. */
.daily-hub {
  overflow: hidden; padding: 20px 0 60px;
  background: var(--background);
}
.daily-shell { max-width: 1600px; }
/* ------------------------------------------------------------- Daily Hero Card */
.daily-hero {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  width: 100%;
  aspect-ratio: 2048 / 768;
  margin: 0 0 28px;
  background-color: #edf4ff;
  background: url('../img/daily-hero-background-v5.webp') center / cover no-repeat;
  border: 1px solid #dce8f8;
  border-radius: 28px;
  box-shadow: 0 14px 36px rgba(30, 64, 175, 0.05);
  padding: 44px calc(57% + 24px) 44px 48px;
  min-height: 0;
  display: flex;
  align-items: center;
}

.daily-hero::before,
.daily-hero::after {
  display: none;
}

.daily-hero-copy {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: 820px;
}

@media (min-width: 901px) {
  .daily-hero {
    display: flex;
    align-items: center;
  }
}

/* Eyebrow Badge */
.daily-hero-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 16px;
  border-radius: var(--radius-pill, 9999px);
  background: #eff6ff;
  border: 1px solid #bfdbfe;
  color: #1d4ed8;
  font-size: 13.5px;
  font-weight: 700;
  margin-bottom: 18px;
  box-shadow: 0 2px 5px rgba(37, 99, 235, 0.035);
}
.daily-hero-badge .icon {
  color: #2563eb;
}

/* Headline */
.daily-hero-title {
  margin: 0 0 18px;
  font-size: clamp(40px, 3.2vw, 52px);
  font-weight: 850;
  line-height: 1.15;
  letter-spacing: -0.035em;
  color: #0f172a;
}
.daily-title-row1 {
  display: block;
  font-size: 1.29em;
  color: #0f172a;
  line-height: 1.18;
  /* คอลัมน์ข้อความกว้างคงที่ 500px ส่วนฟอนต์โตตามจอ พอจอกว้างมากบรรทัดนี้จึง
     ตัดคำ — บังคับให้อยู่บรรทัดเดียวแบบเดียวกับบรรทัด "วิชาละ 10 ข้อ ต่อ วัน" */
  white-space: nowrap;
}
.daily-title-row2 {
  display: block;
  font-size: 1.15em;
  color: #0f172a;
  white-space: nowrap;
  position: relative;
  margin-top: 6px;
  line-height: 1.15;
}
.daily-title-underline-wrap {
  position: relative;
  display: inline-block;
}
.daily-title-curve {
  position: absolute;
  left: 0;
  bottom: -10px;
  width: 100%;
  height: 15px;
  pointer-events: none;
}
.daily-hero-title .c-royal {
  color: #1d4ed8;
  font-weight: 800;
}
.daily-hero-title .c-amber {
  color: #ff9800;
  font-weight: 800;
  font-family: var(--font-num, inherit);
}
.daily-hero-title .c-free {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 3px 14px 5px;
  border-radius: 10px;
  background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%);
  color: #ffffff;
  font-size: 0.76em;
  font-weight: 800;
  line-height: 1.15;
  margin-left: 6px;
  vertical-align: middle;
  box-shadow: 0 5px 14px rgba(37, 99, 235, 0.26);
}

/* Lead text */
.daily-hero-lead {
  margin: 0 0 18px;
  color: #334155;
  font-size: 15.5px;
  line-height: 1.65;
  max-width: 860px;
}

/* CTA Group */
.daily-hero-cta-group {
  display: flex;
  flex-direction: column;
  gap: 0;
}

/* CTA Row */
.daily-hero-cta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
}
.daily-btn-primary {
  min-height: 56px;
  padding: 0 28px;
  border-radius: 16px;
  background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%);
  color: #ffffff;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  border: none;
  box-shadow: 0 10px 22px rgba(37, 99, 235, 0.26), 0 2px 5px rgba(12, 23, 48, 0.06);
  transition: transform var(--t-fast, 150ms), box-shadow var(--t-fast, 150ms);
  cursor: pointer;
  text-decoration: none;
}
.daily-btn-primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 13px 26px rgba(37, 99, 235, 0.32);
  color: #ffffff;
  text-decoration: none;
}
.daily-btn-primary:active {
  transform: translateY(0);
  box-shadow: 0 4px 14px rgba(37, 99, 235, 0.22);
}
.daily-btn-primary .btn-play-icon {
  display: inline-flex;
  transition: transform var(--t-fast, 150ms);
  flex-shrink: 0;
}
.daily-btn-primary .btn-arrow-icon {
  display: inline-flex;
  transition: transform var(--t-fast, 150ms);
  flex-shrink: 0;
  margin-left: 2px;
}
.daily-btn-primary:hover .btn-arrow-icon {
  transform: translateX(3px);
}
.daily-date-pill {
  min-height: 56px;
  padding: 8px 22px;
  border-radius: 16px;
  background: #ffffff;
  border: 1px solid #e2e8f0;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  box-shadow: 0 3px 10px rgba(15, 23, 42, 0.045);
  white-space: nowrap;
}
.daily-date-pill .date-cal-icon {
  color: #2563eb;
  flex-shrink: 0;
}
.daily-date-text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  text-align: left;
}
.daily-date-label {
  font-size: 13.5px;
  font-weight: 700;
  color: #0f172a;
  line-height: 1.2;
}
.daily-date-val {
  font-size: 12px;
  font-weight: 500;
  color: #64748b;
  line-height: 1.2;
}

/* Benefits Row */
.daily-hero-benefits {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  width: auto;
  max-width: 100%;
  position: relative;
  z-index: 2;
  gap: 12px clamp(14px, 1.6vw, 22px);
  margin-top: 18px;
}
.daily-benefit-item {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  white-space: nowrap;
}
.benefit-icon-wrap {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: #eff6ff;
  border: 1px solid #dbeafe;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #2563eb;
  flex-shrink: 0;
}
.benefit-icon-wrap svg,
.benefit-icon-wrap .icon {
  width: 22px;
  height: 22px;
}
.benefit-item-content {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.benefit-title {
  font-size: 15.5px;
  font-weight: 700;
  color: #0f172a;
  line-height: 1.25;
}
.benefit-desc {
  font-size: 13.5px;
  font-weight: 500;
  color: #475569;
  line-height: 1.25;
}

/* The hero art leaves the copy roughly 45% of the card, which the three
   benefits overrun at their full size and wrap into a lopsided 2 + 1. Trimming
   the icon and the gaps keeps them on one line without touching the smaller
   breakpoints, where the copy column is a different width again. */
@media (min-width: 1101px) {
  .daily-hero-benefits { gap: 12px 15px; }
  .daily-benefit-item { gap: 10px; }
  .benefit-icon-wrap { width: 38px; height: 38px; }
  .benefit-icon-wrap svg,
  .benefit-icon-wrap .icon { width: 19px; height: 19px; }
  .benefit-title { font-size: 14.5px; }
  .benefit-desc { font-size: 12.5px; }
}
.benefit-sep {
  display: inline-block;
  width: 1px;
  height: 36px;
  background: #e2e8f0;
  flex-shrink: 0;
}

/* Illustration Column */
.daily-hero-art {
  position: absolute;
  inset: 0 0 0 auto;
  z-index: 1;
  width: 44%;
  height: 100%;
  min-width: 0;
  overflow: hidden;
}
.daily-hero-art img {
  display: block;
  width: 100%;
  max-width: none;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* ------------------------------------------- Sign-in bar / today's progress */
/* One row, one sentence, two buttons — the compact replacement for the notice
   panel that used to occupy a third of the screen. */
.daily-signin-bar {
  display: flex; align-items: center; gap: 16px;
  min-height: 64px; padding: 10px 16px; margin-bottom: 24px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 14px; box-shadow: 0 8px 24px rgba(30, 64, 175, .06);
}
.daily-signin-bar .ic {
  flex: 0 0 auto; width: 38px; height: 38px; display: grid; place-items: center;
  border-radius: 10px; color: var(--primary); background: var(--primary-soft);
}
.daily-signin-bar .body { flex: 1 1 auto; min-width: 0; display: grid; gap: 2px; }
.daily-signin-bar .body b { font-size: 15px; }
.daily-signin-bar .body span { font-size: 13px; color: var(--text-muted); }
.daily-signin-bar .actions { flex: 0 0 auto; display: flex; gap: 9px; flex-wrap: wrap; }

.daily-progress {
  padding: 16px 20px 18px; margin-bottom: 24px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 14px; box-shadow: 0 8px 24px rgba(30, 64, 175, .06);
}
.daily-progress-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.daily-progress-head h2 {
  display: flex; align-items: center; gap: 8px;
  margin: 0; font-size: 16.5px; letter-spacing: -.015em;
}
.daily-progress-head h2 .icon { color: var(--primary); }
.daily-progress-head-meta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; justify-content: flex-end; }
.daily-progress-streak {
  display: inline-flex; align-items: center; gap: 5px;
  color: var(--warning); font-size: 12.5px; font-weight: 700;
}
.daily-progress-count {
  font-family: var(--font-num); font-size: 13.5px; font-weight: 700; color: var(--primary-dark);
}
.daily-progress-stats {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px; margin-top: 14px;
}
.daily-progress-stats > div {
  min-width: 0; padding: 11px 13px;
  background: var(--surface-muted); border-radius: 11px;
}
.daily-progress-stats .k {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--text-muted);
}
.daily-progress-stats .num {
  display: block; margin-top: 4px;
  font-family: var(--font-num); font-size: 21px; font-weight: 800; line-height: 1.15;
}
.daily-progress-stats .num small {
  font-family: var(--font); font-size: 12px; font-weight: 500; color: var(--text-muted);
}
.daily-progress-bar { margin-top: 14px; }
.daily-progress-note {
  display: flex; align-items: center; gap: 7px;
  margin: 10px 0 0; font-size: 12.5px; color: var(--text-muted);
}
.daily-progress-note .icon { color: var(--primary); }
.daily-section-head { margin: 0 0 16px; }
.daily-section-head h2 {
  display: flex; align-items: center; gap: 10px;
  margin: 0 0 5px; font-size: 24px; letter-spacing: -.025em;
}
.daily-section-head .lead { margin: 0; font-size: 13.5px; color: var(--text-muted); }
.daily-section-icon { display: inline-flex; color: var(--primary); }
/* ------------------------------------------- Daily Subjects Section (Target UI) */
.daily-subjects-section {
  background: #ffffff;
  border: 1px solid #e2ebf6;
  border-radius: 24px;
  box-shadow: 0 10px 32px rgba(15, 23, 42, 0.03), 0 1px 3px rgba(15, 23, 42, 0.02);
  padding: 32px 32px 36px;
  margin-top: 28px;
  margin-bottom: 36px;
}

/* Section Header */
.daily-subjects-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}
.daily-subjects-header-left {
  display: flex;
  align-items: center;
  gap: 16px;
  min-width: 0;
}
.daily-subjects-header-icon {
  width: 50px;
  height: 50px;
  min-width: 50px;
  border-radius: 14px;
  background: #eaf2fe;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #1d4ed8;
  flex-shrink: 0;
}
.daily-subjects-header-text {
  min-width: 0;
}
.daily-subjects-title {
  margin: 0 0 4px;
  font-size: 23px;
  font-weight: 800;
  color: #0f172a;
  letter-spacing: -0.02em;
  line-height: 1.25;
}
.daily-subjects-subtitle {
  margin: 0;
  font-size: 15px;
  color: #64748b;
  font-weight: 400;
}
.daily-subjects-summary {
  flex-shrink: 0;
}
.daily-summary-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  background: #f1f5f9;
  border: 1px solid #e2e8f0;
  border-radius: 9999px;
  font-size: 13.5px;
  font-weight: 600;
  color: #475569;
}


/* Anchor Scroll Offsets */
#section-general,
#section-part-a,
#section-part-b,
#section-major {
  scroll-margin-top: 86px;
}

/* Section Block & Headers */
.daily-category-block {
  margin-top: 12px;
}
.daily-block-header {
  margin-bottom: 20px;
}
.daily-block-title-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.daily-block-title {
  margin: 0;
  font-size: 21px;
  font-weight: 800;
  color: #0f172a;
  letter-spacing: -0.01em;
  line-height: 1.3;
}
.daily-block-badge {
  display: inline-flex;
  align-items: center;
  padding: 3px 11px;
  border-radius: 9999px;
  background: #eff6ff;
  border: 1px solid #dbeafe;
  color: #1d4ed8;
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
}
.daily-badge-major {
  background: #f1f5f9;
  border-color: #e2e8f0;
  color: #334155;
}
.daily-block-subtitle {
  margin: 4px 0 0;
  font-size: 14.5px;
  color: #64748b;
  font-weight: 400;
  line-height: 1.5;
}

/* Part Sub-sections (ภาค ก / ภาค ข) */
.daily-part-container {
  margin-top: 22px;
}
.daily-part-container + .daily-part-container {
  margin-top: 30px;
}
.daily-part-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
  padding-bottom: 8px;
  border-bottom: 1px solid #f1f5f9;
}
.daily-part-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 3px 9px;
  border-radius: 6px;
  background: #1e3a8a;
  color: #ffffff;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.02em;
}
.daily-part-title {
  color: #334155;
  font-size: 14.5px;
  font-weight: 700;
}

/* Section Divider (48-64px spacing) */
.daily-section-divider {
  border: 0;
  border-top: 1px solid #e2e8f0;
  margin: 52px 0 40px;
}

/* Major Section Header & Search Toolbar */
.daily-major-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: 22px;
}
.daily-major-header-main {
  min-width: 0;
  flex: 1 1 auto;
}
.daily-major-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}
.daily-major-search {
  min-height: 44px;
  width: 280px;
  max-width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 14px;
  border: 1px solid #cbd5e1;
  border-radius: 11px;
  color: #64748b;
  background: #fff;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.daily-major-search:focus-within {
  border-color: #2563eb;
  outline: none;
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.14);
}
.daily-major-search input {
  width: 100%;
  min-width: 0;
  border: 0;
  outline: 0;
  color: #0f172a;
  background: transparent;
  font: inherit;
  font-size: 14px;
}
.daily-major-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 14px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
  border-radius: 11px;
  color: #475569;
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
}

/* Grid Layout: Desktop 3 cols */
.daily-subject-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
  align-items: stretch;
}
.daily-subject-card[hidden] { display: none; }
.daily-major-empty {
  grid-column: 1 / -1;
  min-height: 180px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: #64748b;
  text-align: center;
  border: 1px dashed #cbd5e1;
  border-radius: 14px;
  padding: 36px 16px;
  background: #fafafa;
}
.daily-major-empty[hidden] { display: none; }
.daily-major-empty b { color: #334155; font-size: 15px; }
.daily-empty-clear-btn {
  margin-top: 8px;
  padding: 6px 16px;
  border-radius: 8px;
  border: 1px solid #cbd5e1;
  background: #ffffff;
  color: #1d4ed8;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.15s ease;
}
.daily-empty-clear-btn:hover {
  background: #eff6ff;
  border-color: #93c5fd;
}

/* Subject Card */
.daily-subject-card {
  position: relative;
  background: #ffffff;
  border: 1px solid #e5eaf2;
  border-radius: 18px;
  padding: 24px 22px 22px;
  box-shadow: 0 3px 12px rgba(15, 23, 42, 0.02);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1), 
              box-shadow 0.2s cubic-bezier(0.16, 1, 0.3, 1), 
              border-color 0.2s ease;
  overflow: hidden;
}
.daily-subject-card:hover {
  transform: translateY(-3px);
  border-color: #cbd5e1;
  box-shadow: 0 12px 28px rgba(29, 78, 216, 0.08), 0 2px 6px rgba(15, 23, 42, 0.03);
}

/* Card Top: Icon, Name, Pill */
.daily-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
}
.daily-card-subject-meta {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  flex: 1 1 auto;
}
.daily-subject-icon-box {
  width: 50px;
  height: 50px;
  min-width: 50px;
  border-radius: 16px;
  background: #edf5ff;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #1d4ed8;
  flex-shrink: 0;
}
.daily-subject-icon-box .thai-char-icon {
  font-family: var(--font);
  font-size: 23px;
  font-weight: 800;
  line-height: 1;
  color: #1d4ed8;
}
.daily-subject-name {
  margin: 0;
  font-size: 16.5px;
  font-weight: 700;
  color: #0f172a;
  line-height: 1.3;
  overflow-wrap: anywhere;
}

/* 10 ข้อ Pill */
.daily-card-count-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px 12px;
  border-radius: 9999px;
  background: #edf5ff;
  border: 1px solid #dbeafe;
  color: #1d4ed8;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  flex-shrink: 0;
}

/* Card Description
   Two lines at most, so one wordy subject cannot make its card taller than
   the rest of the row. Quieter and smaller than the subject name on purpose. */
.daily-card-desc {
  margin: 0 0 16px;
  font-size: 13px;
  font-weight: 400;
  color: #64748b;
  line-height: 1.55;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Wherever the grid has more than one column, every blurb reserves both of its
   lines so cards in different rows still line up. Single-column mobile does
   not need the reserved line and does not get it. */
@media (min-width: 641px) {
  .daily-card-desc { min-height: 2.9em; }
}

/* Card Information: the working time, plus a status row once there is one.
   The hairline separates "what this set is" from "what it costs you". */
.daily-card-info {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 20px;
  padding-top: 14px;
  border-top: 1px solid #eef2f7;
}
.daily-info-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  color: #64748b;
  font-weight: 500;
}
/* The working time is a rule now, not an estimate, so it reads a shade
   stronger than the rows around it without competing with the subject name. */
.daily-time-row {
  color: #475569;
  font-weight: 600;
}
.daily-status-row {
  margin-top: -2px;
}
.daily-status-tag {
  font-size: 13.5px;
  font-weight: 600;
}
.daily-status-tag.is-done {
  color: #059669;
}
.daily-status-tag.is-open {
  color: #d97706;
}
.daily-info-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

/* CTA Button */
.daily-card-cta {
  margin-top: auto;
}
.subject-card-form {
  margin: 0;
  width: 100%;
  display: flex;
}
.daily-subject-btn {
  position: relative;
  width: 100%;
  height: 52px;
  min-height: 52px;
  border-radius: 12px;
  background: #1d4ed8;
  color: #ffffff !important;
  font-family: inherit;
  font-size: 15.5px;
  font-weight: 700;
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  text-decoration: none !important;
  transition: background-color 0.18s ease, transform 0.18s ease, box-shadow 0.18s ease;
  box-shadow: 0 2px 8px rgba(29, 78, 216, 0.18);
  padding: 0 36px 0 20px;
}
.daily-subject-btn:hover {
  background: #1e40af;
  transform: translateY(-1px);
  box-shadow: 0 6px 18px rgba(29, 78, 216, 0.28);
}
.daily-subject-btn:active {
  transform: translateY(0);
}
.daily-subject-btn .btn-arrow {
  position: absolute;
  right: 18px;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.18s ease;
}
.daily-subject-btn:hover .btn-arrow {
  transform: translateY(-50%) translateX(2px);
}
.daily-subject-btn:disabled {
  background: #94a3b8;
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
}
.daily-done-btn-group {
  display: flex;
  gap: 8px;
  width: 100%;
}
.daily-done-btn-group .daily-subject-btn {
  flex: 1 1 50%;
  padding: 0 8px;
  font-size: 13.5px;
}
.daily-btn-secondary {
  background: #f8fafc !important;
  color: #1d4ed8 !important;
  box-shadow: none !important;
  border: 1px solid #cbd5e1 !important;
}
.daily-btn-secondary:hover {
  background: #eff6ff !important;
  border-color: #93c5fd !important;
}
.daily-btn-warning {
  background: #d97706 !important;
  box-shadow: 0 2px 8px rgba(217, 119, 6, 0.22) !important;
}
.daily-btn-warning:hover {
  background: #b45309 !important;
  box-shadow: 0 6px 18px rgba(217, 119, 6, 0.32) !important;
}

/* ------------------------------------------- Special Card "สุ่มรวมทุกวิชา" */
.daily-subject-card-mixed {
  background: linear-gradient(135deg, #ffffff 0%, #fffdf8 55%, #fffbeb 100%);
  border: 1px solid #fde047;
  box-shadow: 0 4px 16px rgba(217, 119, 6, 0.06);
}
.daily-subject-card-mixed:hover {
  border-color: #f59e0b;
  box-shadow: 0 12px 28px rgba(217, 119, 6, 0.12), 0 2px 6px rgba(15, 23, 42, 0.03);
}
.daily-subject-icon-box.is-mixed {
  background: #fef3c7;
  border: 1px solid #fde68a;
  color: #d97706;
}
.daily-card-count-badge.is-mixed {
  background: #fffbeb;
  border: 1px solid #fde68a;
  color: #b45309;
}
.mixed-card-sparkles {
  position: absolute;
  top: 88px;
  right: 10px;
  pointer-events: none;
  z-index: 0;
}


.daily-history-head { margin-top: 40px; }
.daily-archive { overflow: hidden; border-radius: 14px; box-shadow: 0 6px 22px rgba(30, 64, 175, .05); }
/* A short list of days, not a table: one line of date, one of summary, and an
   action on the right. */
.daily-archive-row {
  min-height: 58px; display: flex; align-items: center; gap: 14px;
  padding: 8px 18px; color: inherit; text-decoration: none;
  background: var(--surface); transition: background var(--t-fast);
}
.daily-archive-row + .daily-archive-row { border-top: 1px solid var(--border); }
.daily-archive-row:hover { background: #f8fafc; text-decoration: none; }
.daily-archive-row.is-today { background: var(--primary-soft); }
.daily-archive-row.is-today:hover { background: var(--primary-soft-2, var(--primary-soft)); }
.daily-archive-copy { flex: 1 1 auto; min-width: 0; display: grid; gap: 2px; }
.daily-archive-date { display: flex; align-items: center; gap: 7px; font-size: 14.5px; font-weight: 700; }
.daily-archive-meta { color: var(--text-muted); font-size: 12.5px; }
.daily-archive-meta b { color: var(--text); font-family: var(--font-num); }
.daily-archive-action {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 5px;
  color: var(--primary); font-size: 12.5px; font-weight: 700;
  transition: transform var(--t-fast);
}
.daily-archive-row:hover .daily-archive-action { transform: translateX(2px); }
.daily-archive-more {
  display: flex; align-items: center; justify-content: center; gap: 12px;
  margin-top: 14px; flex-wrap: wrap;
}
.daily-archive-page { font-size: 12.5px; color: var(--text-subtle); }

@media (max-width: 1024px) {
  .daily-subjects-section {
    padding: 28px 24px 32px;
  }
  .daily-subject-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 18px;
  }
}

@media (max-width: 1100px) {
  .daily-hero {
    /* Below 1100 the copy needs more lines than the art's 2.684 ratio leaves
       room for, so the card grows instead of clipping its own text. */
    aspect-ratio: auto;
    min-height: 0;
    display: flex;
    align-items: center;
    padding: 36px 46% 36px 32px;
    background:
      linear-gradient(90deg, rgba(237, 244, 255, 0.82) 0%, rgba(237, 244, 255, 0.78) 48%, rgba(237, 244, 255, 0.52) 64%, rgba(237, 244, 255, 0) 80%),
      url('../img/daily-hero-background-v5.webp') right center / cover no-repeat;
    border-radius: 24px;
  }
  .daily-hero-badge { display: none !important; }
  .daily-hero-title { font-size: clamp(32px, 3.6vw, 40px); margin-bottom: 14px; }
  .daily-hero-lead { font-size: 14.5px; line-height: 1.6; margin-bottom: 16px; color: #334155; }
  .daily-hero-benefits { gap: 14px; margin-top: 16px; }
  .daily-benefit-item { gap: 10px; }
  .benefit-icon-wrap { width: 38px; height: 38px; }
  .benefit-icon-wrap svg { width: 19px; height: 19px; }
  .benefit-title { font-size: 14px; }
  .benefit-desc { font-size: 12.5px; color: #475569; }
  .benefit-sep { height: 30px; }
  .daily-progress-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
  .daily-hub { padding-top: 18px; }
  /* This block is what 768px renders, so its values ARE the master. Each clamp
     resolves to the master's number at 768 and scales down from there; the
     40% artwork reserve, the left-to-right scrim and the `right center`
     background are frozen and never redefined by a narrower breakpoint. */
  .daily-hero {
    padding: clamp(14px, 3.125vw, 24px) 40% clamp(14px, 3.125vw, 24px) clamp(12px, 2.344vw, 18px);
    border-radius: clamp(16px, 2.604vw, 20px);
    min-height: clamp(180px, 29.95vw, 230px);
  }
  .daily-hero-title {
    font-size: clamp(18px, 3.385vw, 26px);
    line-height: 1.26;
    margin-bottom: clamp(7px, 1.302vw, 10px);
  }
  .daily-hero-lead {
    margin-bottom: clamp(8px, 1.563vw, 12px);
    font-size: clamp(10.5px, 1.667vw, 12.8px);
    line-height: 1.55;
    color: #334155;
  }
  .daily-hero-lead br { display: none; }
  .daily-hero-benefits { gap: clamp(5px, 1.042vw, 8px) clamp(7px, 1.563vw, 12px); margin-top: clamp(4px, 0.781vw, 6px); }
  .daily-benefit-item { width: auto; gap: clamp(5px, 0.911vw, 7px); }
  .benefit-icon-wrap { width: clamp(24px, 3.906vw, 30px); height: clamp(24px, 3.906vw, 30px); }
  .benefit-icon-wrap svg { width: clamp(12px, 1.953vw, 15px); height: clamp(12px, 1.953vw, 15px); }
  .benefit-title { font-size: clamp(10px, 1.536vw, 11.8px); }
  .benefit-desc { font-size: clamp(9px, 1.367vw, 10.5px); color: #475569; }
  .benefit-sep { display: none; }
  /* Daily Subjects Section Mobile */
  .daily-subjects-section {
    padding: 22px 16px 26px;
    border-radius: 20px;
    margin-top: 20px;
    margin-bottom: 28px;
  }
  .daily-subjects-header {
    gap: 12px;
    margin-bottom: 20px;
  }
  .daily-major-header {
    flex-direction: column;
    align-items: stretch;
    gap: 14px;
  }
  .daily-major-toolbar {
    width: 100%;
    gap: 10px;
  }
  .daily-major-search {
    flex: 1 1 auto;
    width: auto;
  }
  .daily-section-divider {
    margin: 36px 0 28px;
  }
  .daily-subjects-header-icon {
    width: 44px;
    height: 44px;
    min-width: 44px;
    border-radius: 12px;
  }
  .daily-subjects-title {
    font-size: 20px;
  }
  .daily-subjects-subtitle {
    font-size: 13.5px;
  }
  .daily-subject-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px;
  }
  .daily-subject-card {
    padding: 20px 18px 18px;
    border-radius: 16px;
  }
  .daily-subject-icon-box {
    width: 46px;
    height: 46px;
    min-width: 46px;
  }
  .daily-subject-name {
    font-size: 16px;
  }
  .daily-subject-btn {
    height: 50px;
    min-height: 50px;
    font-size: 15px;
  }
  .daily-section-head h2 { font-size: 22px; }
  .daily-signin-bar { flex-wrap: wrap; }
  .daily-signin-bar .actions { flex: 1 1 100%; }
  .daily-signin-bar .actions .btn { flex: 1 1 45%; min-height: 44px; }
}

@media (max-width: 640px) {
  .daily-subject-grid {
    grid-template-columns: 1fr;
    gap: 14px;
  }
  .daily-block-title {
    font-size: 19px;
  }
  .daily-part-header {
    gap: 8px;
  }
  .daily-major-toolbar {
    flex-wrap: wrap;
    gap: 8px;
  }
  .daily-major-search {
    flex: 1 1 100%;
    width: 100%;
  }
  .daily-major-count {
    padding-left: 2px;
  }
}

@media (max-width: 560px) {
  .daily-hub { padding-bottom: 52px; }
  /* No .daily-hero rules here on purpose. This block used to re-cut the
     artwork reserve to 38% and re-set the type, which made a small phone a
     different composition from the 768px master; the <=760 clamps already
     cover this range continuously. */
  .daily-subject-grid { grid-template-columns: 1fr; gap: 12px; }
  .daily-major-toolbar { flex-wrap: wrap; gap: 8px; }
  .daily-major-search { flex: 1 1 100%; }
  .daily-major-count { padding-left: 2px; }
  .daily-card-top { align-items: flex-start; }
  .daily-progress { padding: 14px; }
  .daily-progress-head { align-items: flex-start; }
  .daily-progress-head-meta { gap: 6px; }
  .daily-progress-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .daily-progress-stats > div { padding: 10px; }
  .daily-progress-stats .num { font-size: 19px; }
  .daily-history-head { margin-top: 32px; }
  .daily-archive-row { gap: 10px; padding-inline: 14px; }
}

@media (max-width: 430px) {
  .daily-signin-bar { align-items: flex-start; gap: 10px; }
  .daily-signin-bar .body { padding-top: 7px; }
  .daily-signin-bar .actions { flex-direction: column; }
  .daily-signin-bar .actions .btn { width: 100%; flex-basis: auto; }
  .daily-progress-head-meta { display: grid; justify-items: end; }
  .daily-archive-action { font-size: 0; gap: 0; }
  .daily-archive-action .icon { width: 18px; height: 18px; }
}

/* Exam card */
.exam-card { padding: var(--space); display: flex; flex-direction: column; gap: 10px; height: 100%; }
.exam-card .top { display: flex; gap: 8px; flex-wrap: wrap; }
.exam-card h3 { font-size: 16.5px; margin: 0; line-height: 1.45; }
.exam-card .desc {
  font-size: 13.5px; color: var(--text-muted); margin: 0;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.exam-card .facts {
  display: flex; gap: var(--space); flex-wrap: wrap; margin-top: auto;
  padding-top: 11px; border-top: 1px solid var(--border);
  font-size: 12.5px; color: var(--text-muted);
}
.exam-card .facts span { display: inline-flex; align-items: center; gap: 5px; }

/* The home page shows eight sets at once, where the point is to scan titles and
   spot what is free. Four to a row and no description: the same card, denser,
   rather than a second card component to maintain. */
.exam-grid-compact { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: var(--space); }
.exam-grid-compact .exam-card { padding: 15px; gap: 9px; }
.exam-grid-compact .exam-card .desc { display: none; }
/* Difficulty goes too. At this size the badge row is what the eye lands on
   first, and category plus "is it free" are the two facts worth that place. */
.exam-grid-compact .exam-card .badge-muted { display: none; }
.exam-grid-compact .exam-card h3 { font-size: 15.5px; }
.exam-grid-compact .exam-card .facts { gap: 13px; font-size: 12px; }

/* Ranking row */
.rank-row {
  display: flex; align-items: center; gap: 13px; padding: 11px 14px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface);
}
.rank-row + .rank-row { margin-top: 8px; }
.rank-row.is-me { border-color: var(--primary); background: var(--primary-soft); }
.rank-no {
  width: 38px; height: 38px; flex: 0 0 auto; border-radius: 11px;
  display: grid; place-items: center; background: var(--surface-muted);
  font-family: var(--font-num); font-weight: 700; font-size: 15px; color: var(--text-muted);
}
.rank-row.top-1 .rank-no { background: #f5b400; color: #fff; }
.rank-row.top-2 .rank-no { background: #9aa6bd; color: #fff; }
.rank-row.top-3 .rank-no { background: #c07b30; color: #fff; }
.rank-main { min-width: 0; flex: 1 1 auto; }
.rank-name { font-weight: 600; font-size: 14.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rank-meta { font-size: 12.5px; color: var(--text-muted); display: flex; gap: 10px; flex-wrap: wrap; margin-top: 1px; }
.rank-score { text-align: right; flex: 0 0 auto; }
.rank-score .s { font-family: var(--font-num); font-weight: 700; font-size: 16px; }
.rank-score .p { font-size: 12px; color: var(--text-muted); font-family: var(--font-num); }

/* Article card. Every card carries a real picture — an editor's upload or one
   of the drawn covers — so the strip never degrades into a row of grey slabs,
   and the category rides on the picture the way it does on the target. */
.article-card { overflow: hidden; height: 100%; }
.article-card .cover-wrap { position: relative; display: block; overflow: hidden; }
.article-card .cover {
  aspect-ratio: 16 / 9; background: var(--surface-muted);
  object-fit: cover; width: 100%; display: block;
  transition: transform var(--t-slow);
}
.article-card:hover .cover { transform: scale(1.045); }
.article-card .cover-tag {
  position: absolute; left: 10px; bottom: 10px; z-index: 1;
  box-shadow: 0 2px 8px rgba(6, 16, 45, .28);
}
.article-card .body { padding: var(--space); display: flex; flex-direction: column; gap: 7px; }
.article-card h3 { font-size: 16px; line-height: 1.45; margin: 0; }
.article-card .excerpt {
  font-size: 13.5px; color: var(--text-muted); margin: 0;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* On the home page the articles are a strip of five, not a reading list: the
   picture and the headline do the work and the excerpt is dropped, because at
   this width two clamped lines of it are unreadable anyway. */
.article-grid { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--space); }
.article-grid .article-card .body { padding: 13px; gap: 6px; }
.article-grid .article-card h3 {
  font-size: 14.5px;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.article-grid .article-card .excerpt { display: none; }
.article-grid .article-card .badge { font-size: 11.5px; }

/* -------------------------------------------------------- ARTICLES LANDING
   Editorial layout for /articles only. The public header, footer and the
   reusable article cards used elsewhere deliberately remain untouched. */
.articles-page {
  max-width: 1180px;
  padding-top: 8px;
  padding-bottom: 12px;
}
.articles-hero {
  position: relative;
  height: 252px;
  min-height: 252px;
  display: grid;
  grid-template-columns: minmax(0, .9fr) minmax(480px, 1.1fr);
  align-items: stretch;
  overflow: hidden;
  border: 1px solid #e7edf7;
  border-radius: 16px;
  background: #f6f9ff;
}
.articles-hero-copy {
  position: absolute;
  inset: 0 auto 0 0;
  z-index: 3;
  width: 54%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 22px 16px 20px 28px;
}
.articles-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  width: fit-content;
  margin-bottom: 9px;
  padding: 4px 11px;
  border-radius: var(--radius-pill);
  background: #eaf1ff;
  color: var(--primary);
  font-size: 12px;
  font-weight: 700;
}
.articles-hero h1 {
  margin: 0 0 5px;
  color: #0b1838;
  font-size: clamp(29px, 2.45vw, 34px);
  line-height: 1.15;
  letter-spacing: -.035em;
}
.articles-hero h1 span { color: #245bea; }
.articles-hero-lead {
  margin-bottom: 5px;
  color: #183777;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.5;
}
.articles-hero-description {
  margin: 0;
  color: #647493;
  font-size: 12px;
  line-height: 1.6;
}
.articles-hero-points {
  display: flex;
  align-items: center;
  gap: 10px 18px;
  flex-wrap: wrap;
  list-style: none;
  margin: 13px 0 0;
  padding: 0;
  color: #354b73;
  font-size: 11px;
  font-weight: 600;
}
.articles-hero-points li { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.articles-hero-points .icon { color: #1e5bea; }
.articles-hero-points .icon circle { fill: #1e5bea; stroke: #1e5bea; }
.articles-hero-points .icon path { stroke: #fff; }
.articles-hero-visual {
  position: absolute;
  inset: 0 0 0 auto;
  width: 70%;
  min-width: 0;
  isolation: isolate;
}
.articles-hero-visual::before {
  content: '';
  position: absolute;
  inset: 0 auto 0 -1px;
  z-index: 1;
  width: 34%;
  background: linear-gradient(90deg, #f6f9ff 8%, rgba(246, 249, 255, .96) 46%, rgba(246, 249, 255, 0));
  pointer-events: none;
}
.articles-hero-visual img {
  width: 100%;
  height: 100%;
  min-height: 252px;
  display: block;
  object-fit: cover;
  object-position: center;
  filter: saturate(.9) contrast(.98);
}
.articles-quote,
.articles-book-label {
  position: absolute;
  z-index: 2;
  color: #2452a2;
  font-style: italic;
  transform: rotate(-6deg);
  text-shadow: 0 1px 0 rgba(255, 255, 255, .9);
}
.articles-quote { font-size: 14px; font-weight: 600; line-height: 1.45; }
.articles-quote-left { top: 78px; left: 0; text-align: center; }
.articles-quote-right { top: 72px; right: 10px; font-size: 13px; transform: rotate(7deg); }
.articles-book-label {
  left: 72%;
  min-width: 62px;
  padding: 1px 8px;
  border-radius: 4px;
  background: rgba(12, 38, 91, .92);
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  line-height: 1.35;
  text-align: center;
  text-transform: uppercase;
  transform: translateX(-50%) rotate(-1deg);
}
.articles-book-label.is-plan { top: 150px; color: #fff; text-shadow: 0 1px 2px rgba(2, 29, 84, .7); }
.articles-book-label.is-practice { top: 181px; color: #fff; text-shadow: 0 1px 2px rgba(2, 29, 84, .7); }
.articles-book-label.is-pass { top: 215px; color: #fff; text-shadow: 0 1px 2px rgba(2, 29, 84, .7); }
.articles-hero-note {
  position: absolute;
  z-index: 3;
  display: block;
  color: #234c97;
  font-size: 10.5px;
  font-style: italic;
  font-weight: 700;
  line-height: 1.45;
  text-align: center;
  transform: rotate(-4deg);
}
.articles-hero-note.is-quote {
  top: 18px;
  right: 20px;
  padding: 11px 12px;
  border: 1px solid rgba(225, 210, 143, .55);
  background: rgba(255, 252, 226, .88);
  box-shadow: 0 5px 16px rgba(39, 71, 123, .08);
}
.articles-hero-note.is-goal { right: 21px; bottom: 18px; transform: rotate(5deg); }
.articles-hero-note.is-goal strong { color: #1e5bea; font-size: 15px; }

.articles-tools {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 16px 0;
}
.articles-tabs {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  flex: 1 1 auto;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 2px;
}
.articles-tabs::-webkit-scrollbar { display: none; }
.articles-tab {
  min-height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex: 0 0 auto;
  padding: 7px 17px;
  border: 1px solid #dfe5ef;
  border-radius: var(--radius-pill);
  background: #fff;
  color: #354563;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  transition: border-color var(--t-fast), background var(--t-fast), color var(--t-fast), transform var(--t-fast);
}
.articles-tab:hover {
  border-color: var(--primary-border);
  background: var(--primary-soft);
  color: var(--primary);
  text-decoration: none;
}
.articles-tab.is-active {
  border-color: var(--primary);
  background: var(--primary-grad);
  color: #fff;
  box-shadow: 0 5px 13px rgba(28, 71, 204, .18);
}
.articles-search {
  width: 238px;
  min-height: 40px;
  position: relative;
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  overflow: hidden;
  border: 1px solid #dfe5ef;
  border-radius: var(--radius-pill);
  background: #fff;
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.articles-search:focus-within {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--focus-ring);
}
.articles-search-icon {
  display: inline-flex;
  margin-left: 13px;
  color: #7b89a3;
}
.articles-search input {
  width: 100%;
  min-width: 0;
  height: 38px;
  padding: 6px 5px 6px 9px;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 13px;
}
.articles-search input::-webkit-search-cancel-button { cursor: pointer; }
.articles-search button {
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  border: 0;
  background: transparent;
  color: var(--primary);
  cursor: pointer;
}
.articles-search button:hover { background: var(--primary-soft); }
.articles-result-summary {
  margin: -4px 0 14px;
  color: var(--text-muted);
  font-size: 13px;
}
.articles-empty { text-align: center; }

.articles-feature-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.82fr) minmax(285px, .88fr);
  gap: 14px;
  align-items: stretch;
}
.articles-feature-layout.is-single { grid-template-columns: 1fr; }
.articles-feature-main,
.articles-recommended-card,
.articles-standard-card {
  position: relative;
  min-width: 0;
  overflow: hidden;
  border: 1px solid #e2e8f1;
  border-radius: 14px;
  background: #fff;
  box-shadow: 0 4px 16px rgba(14, 31, 68, .055);
  color: var(--text);
  text-decoration: none;
  transition: transform var(--t), border-color var(--t), box-shadow var(--t);
}
.articles-feature-main:hover,
.articles-recommended-card:hover,
.articles-standard-card:hover {
  transform: translateY(-3px);
  border-color: #c9d7ef;
  box-shadow: 0 12px 28px rgba(14, 39, 91, .11);
  color: var(--text);
  text-decoration: none;
}
.articles-feature-main {
  min-height: 292px;
  display: block;
  color: #fff;
  background: #0b1838;
}
.articles-feature-main:hover { color: #fff; }
.articles-feature-main > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  transition: transform var(--t-slow);
}
.articles-feature-main:hover > img { transform: scale(1.025); }
.articles-feature-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(4, 17, 45, .94) 0%, rgba(4, 18, 46, .77) 45%, rgba(4, 18, 46, .15) 100%);
}
.articles-feature-top {
  position: absolute;
  z-index: 2;
  top: 18px;
  left: 20px;
  right: 20px;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
}
.articles-category-tag {
  display: inline-flex;
  align-items: center;
  min-height: 27px;
  padding: 4px 13px;
  border: 1px solid #cbdcff;
  border-radius: var(--radius-pill);
  background: rgba(248, 251, 255, .95);
  color: #2759ca;
  font-size: 11.5px;
  font-weight: 700;
  white-space: nowrap;
}
.articles-recommended-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 30px;
  padding: 5px 13px;
  border: 1px solid #f2d28f;
  border-radius: var(--radius-pill);
  background: #fff4d8;
  color: #945000;
  font-size: 11.5px;
  font-weight: 700;
}
.articles-feature-content {
  position: absolute;
  z-index: 2;
  left: 22px;
  right: 32%;
  bottom: 18px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.articles-feature-content h2 {
  margin: 0 0 7px;
  color: #fff;
  font-size: clamp(22px, 2.4vw, 29px);
  line-height: 1.35;
  letter-spacing: -.02em;
}
.articles-feature-excerpt {
  margin-bottom: 10px;
  color: rgba(255, 255, 255, .86);
  font-size: 12.5px;
  line-height: 1.65;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.articles-read-cta {
  min-height: 33px;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 9px;
  padding: 5px 15px;
  border-radius: var(--radius-pill);
  background: #fff;
  color: #153a8f;
  font-size: 12px;
  font-weight: 700;
}
.articles-feature-note {
  position: absolute;
  z-index: 2;
  right: 22px;
  bottom: 18px;
  color: rgba(255, 255, 255, .82);
  font-size: 13px;
  font-style: italic;
  line-height: 1.35;
  text-align: center;
  transform: rotate(-6deg);
}
.articles-meta {
  display: flex;
  align-items: center;
  gap: 15px;
  color: #7b879d;
  font-size: 11.5px;
  line-height: 1.4;
}
.articles-meta > span { display: inline-flex; align-items: center; gap: 6px; }
.articles-meta.is-light { color: rgba(255, 255, 255, .8); }

.articles-recommended-card,
.articles-standard-card { display: flex; flex-direction: column; }
.articles-card-media {
  position: relative;
  display: block;
  overflow: hidden;
  background: var(--surface-muted);
}
.articles-card-media > img {
  width: 100%;
  aspect-ratio: 16 / 8.5;
  display: block;
  object-fit: cover;
  transition: transform var(--t-slow);
}
.articles-recommended-card:hover .articles-card-media > img,
.articles-standard-card:hover .articles-card-media > img { transform: scale(1.035); }
.articles-card-media .articles-category-tag {
  position: absolute;
  top: 12px;
  left: 12px;
}
.articles-card-body {
  min-height: 0;
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  padding: 14px 15px 13px;
}
.articles-card-body h2 {
  margin: 0 0 7px;
  color: #101c38;
  font-size: 16px;
  line-height: 1.42;
  letter-spacing: -.01em;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.articles-card-excerpt {
  color: #687690;
  font-size: 12.5px;
  line-height: 1.62;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.articles-card-footer {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 8px;
  margin-top: auto;
  padding-top: 12px;
}
.articles-card-arrow {
  width: 31px;
  height: 31px;
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  border: 1px solid #b9ceff;
  border-radius: 50%;
  color: var(--primary);
  transition: background var(--t-fast), color var(--t-fast), transform var(--t-fast);
}
.articles-recommended-card:hover .articles-card-arrow,
.articles-standard-card:hover .articles-card-arrow {
  background: var(--primary);
  color: #fff;
  transform: translateX(2px);
}
.articles-standard-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  margin-top: 14px;
}
.articles-standard-card .articles-card-body { min-height: 150px; }
.articles-standard-card .articles-card-media > img { aspect-ratio: 16 / 7.1; }

@media (max-width: 1050px) {
  .articles-hero { grid-template-columns: minmax(0, 1fr) minmax(400px, .95fr); }
  .articles-quote-left { display: none; }
  .articles-book-label { left: 54%; }
  .articles-tools { align-items: stretch; flex-direction: column; }
  .articles-search { width: min(100%, 420px); }
  .articles-feature-layout { grid-template-columns: minmax(0, 1.5fr) minmax(270px, .9fr); }
  .articles-feature-content { right: 22%; }
}

@media (max-width: 820px) {
  .articles-page { padding-top: 4px; }
  /* Same composition as the desktop, scaled: the copy stays pinned left and
     the image stays pinned right. They used to unpin and stack, which turned
     this hero into a different design below 820px. */
  .articles-hero {
    grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr);
    height: 212px;
    min-height: 212px;
  }
  .articles-hero-copy { width: 56%; padding: 22px 0 22px 24px; }
  .articles-hero-visual { width: 68%; }
  .articles-hero-visual img { min-height: 212px; }
  .articles-quote-left { display: block; left: 8%; top: 68px; }
  .articles-feature-layout { grid-template-columns: 1fr; }
  .articles-feature-main { min-height: 320px; }
  .articles-recommended-card { display: grid; grid-template-columns: minmax(250px, .9fr) 1fr; }
  .articles-recommended-card .articles-card-media > img { height: 100%; aspect-ratio: auto; }
  .articles-standard-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 600px) {
  .articles-page { padding-inline: 16px; }
  /* The copy/visual split (56% / 68%) is the 768px master's and is frozen —
     only the box height and the type scale below it. */
  /* The copy is absolutely positioned, so it cannot push this box taller — the
     height has to be stated. 264px clears the tallest wrap (at 360px the points list runs to three lines),
     and being one value for every phone is what makes 430/390/375/360 render
     identically rather than each clipping by a different amount. */
  .articles-hero { border-radius: 15px; height: 264px; min-height: 264px; }
  .articles-hero-copy { padding: clamp(12px, 2.86vw, 22px) 0 clamp(12px, 2.86vw, 22px) clamp(13px, 3.13vw, 24px); }
  .articles-hero h1 { font-size: clamp(18px, 3.39vw, 26px); line-height: 1.22; }
  .articles-hero h1 span { display: block; }
  .articles-hero-lead { font-size: clamp(11.5px, 1.82vw, 14px); line-height: 1.38; }
  .articles-hero-description { font-size: clamp(10.2px, 1.56vw, 12px); line-height: 1.45; }
  .articles-hero-description br { display: none; }
  .articles-hero-points { gap: clamp(3px, 0.65vw, 5px); font-size: clamp(10.2px, 1.56vw, 12px); }
  .articles-hero-points li { gap: clamp(4px, 0.78vw, 6px); }
  .articles-hero-points .icon { width: clamp(12px, 1.82vw, 14px); height: clamp(12px, 1.82vw, 14px); }
  /* Follow the box now that it can grow, so the artwork never leaves a gap. */
  .articles-hero-visual img { min-height: 100%; height: 100%; }
  .articles-quote { font-size: 11px; }
  .articles-quote-left { top: 54px; left: 3%; }
  .articles-quote-right { top: 42px; right: 4px; font-size: 10px; }
  .articles-book-label { font-size: 11px; left: 57%; }
  .articles-book-label.is-plan { top: 59px; }
  .articles-book-label.is-practice { top: 82px; }
  .articles-book-label.is-pass { top: 105px; }
  .articles-tools { gap: 10px; margin: 12px 0 14px; }
  .articles-tabs { margin-inline: -2px; padding-bottom: 3px; }
  .articles-tab { min-height: 42px; padding-inline: 15px; }
  .articles-search { width: 100%; min-height: 44px; }
  .articles-search input,
  .articles-search button { height: 42px; }
  .articles-feature-main { min-height: 390px; }
  .articles-feature-overlay { background: linear-gradient(0deg, rgba(4, 17, 45, .96) 0%, rgba(4, 18, 46, .72) 62%, rgba(4, 18, 46, .14) 100%); }
  .articles-feature-content { left: 18px; right: 18px; bottom: 17px; }
  .articles-feature-content h2 { font-size: 22px; }
  .articles-feature-note { display: none; }
  .articles-recommended-card { display: flex; }
  .articles-recommended-card .articles-card-media > img { height: auto; aspect-ratio: 16 / 8.5; }
  .articles-standard-grid { grid-template-columns: 1fr; }
  .articles-standard-card .articles-card-media > img { aspect-ratio: 16 / 8; }
  .articles-standard-card .articles-card-body { min-height: 145px; }
  .articles-meta { gap: 11px; font-size: 11px; }
}

:root[data-theme="dark"] .articles-hero {
  border-color: var(--border);
  background: linear-gradient(112deg, #101a34 0%, #121e3b 52%, #17284d 100%);
}
:root[data-theme="dark"] .articles-hero h1,
:root[data-theme="dark"] .articles-card-body h2 { color: var(--text); }
:root[data-theme="dark"] .articles-hero-lead { color: #9cb5ff; }
:root[data-theme="dark"] .articles-hero-visual::before {
  background: linear-gradient(90deg, #121e3b 8%, rgba(18, 30, 59, 0));
}
:root[data-theme="dark"] .articles-tab,
:root[data-theme="dark"] .articles-search,
:root[data-theme="dark"] .articles-recommended-card,
:root[data-theme="dark"] .articles-standard-card { background: var(--surface); border-color: var(--border); }
:root[data-theme="dark"] .articles-tab { color: var(--text-muted); }
:root[data-theme="dark"] .articles-tab.is-active { color: var(--primary-contrast); }
:root[data-theme="dark"] .articles-category-tag { background: rgba(17, 26, 51, .95); border-color: var(--primary-border); color: var(--primary); }

@media (max-width: 820px) {
  :root[data-theme="dark"] .articles-hero-visual::before {
    background: linear-gradient(180deg, #121e3b 8%, rgba(18, 30, 59, 0));
  }
}

/* Pricing plans. Four cards of equal height where only the price changes, so
   the price is the one element given real scale and everything else is kept
   deliberately quiet; the recommended plan is marked with gold and a raised
   surface rather than a larger card, which would break the row. */
.plan-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 20px; align-items: stretch; padding-top: 12px;
}
.plan {
  position: relative; display: flex; flex-direction: column;
  padding: var(--space-md) var(--space);
}
.plan-badge {
  position: absolute; top: -12px; left: 50%; transform: translateX(-50%);
  white-space: nowrap; box-shadow: var(--shadow-sm);
}
.plan-name { font-size: 17px; margin: 0 0 3px; text-align: center; }
.plan-term { display: block; text-align: center; font-size: 12.5px; color: var(--text-subtle); }
.plan-price {
  display: flex; align-items: baseline; justify-content: center; gap: 5px;
  margin-top: var(--space); font-family: var(--font-num);
}
.plan-price .amount { font-size: 40px; font-weight: 800; line-height: 1; letter-spacing: -.03em; }
.plan-price .unit { font-size: 14px; font-weight: 600; color: var(--text-muted); }
.plan-was { text-align: center; font-size: 12.5px; color: var(--text-muted); margin-top: 6px; }
.plan-was s { opacity: .8; }
.plan-save { color: var(--success); font-weight: 700; margin-left: 5px; }
.plan-desc {
  font-size: 13px; color: var(--text-muted); line-height: 1.6;
  text-align: center; margin: var(--space) 0 0;
  padding-top: var(--space); border-top: 1px solid var(--border);
}
.plan-features { list-style: none; padding: 0; margin: var(--space) 0 var(--space-md); display: grid; gap: 9px; }
.plan-features li { display: flex; align-items: flex-start; gap: 9px; font-size: 13.5px; line-height: 1.5; }
.plan-features .icon { color: var(--success); margin-top: 2px; }
.plan-action { margin-top: auto; }

/* The recommended plan. */
.plan-featured {
  border-color: var(--vip-border); border-width: 2px;
  box-shadow: 0 12px 30px -10px rgba(217, 119, 6, .3);
}
.plan-featured .plan-price .amount { color: var(--vip); }

/* ------------------------------------------------ PACKAGES V2 PRICING STYLES */

/* Hero visual: headline/mascot/benefits are baked into the background image;
   the .package-hero copy below is kept only for SEO/screen readers (.sr-only). */
.vip-hero {
  position: relative;
  margin-bottom: 20px;
}
.vip-hero-bg {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-lg);
}

.package-hero {
  padding-top: 6px;
  margin-bottom: 20px;
}
.package-hero h1 {
  font-size: 29px;
  font-weight: 800;
  letter-spacing: -.02em;
  margin: 8px 0 8px;
}
.package-hero .lead {
  max-width: 650px;
  margin-inline: auto;
  font-size: 15px;
  line-height: 1.55;
  color: var(--text-muted);
}
.eyebrow-vip {
  background: var(--vip-soft);
  border-color: var(--vip-border);
  color: var(--vip-strong);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* 3-card Trio Grid */
.plan-grid-trio {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  align-items: stretch;
  margin-bottom: 20px;
  padding-top: 14px;
}

.plan-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 28px 22px 22px;
  transition: transform var(--t-fast), box-shadow var(--t-fast);
}

.plan-card .plan-badge {
  position: absolute;
  top: -12px;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  box-shadow: var(--shadow-sm);
  padding: 4px 12px;
  font-size: 12px;
  font-weight: 700;
  border-radius: 999px;
}

.badge-outline-neutral {
  background: var(--surface);
  border: 1px solid var(--border-strong, #cbd5e1);
  color: var(--text-muted);
}

.badge-vip-solid {
  background: var(--vip-gradient);
  color: #fff;
  border: none;
  box-shadow: 0 4px 10px rgba(217, 119, 6, .35);
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

/* Primary Recommended Card (365 วัน) */
.plan-card-hero {
  border: 2px solid var(--vip-border);
  background: linear-gradient(180deg, rgba(255, 246, 232, 0.5) 0%, var(--surface) 35%);
  box-shadow: 0 10px 26px -8px rgba(217, 119, 6, 0.2);
}

.plan-card-popular {
  border: 1.5px solid var(--primary-border);
  box-shadow: var(--shadow-xs);
}

.plan-card-trial {
  border: 1px solid var(--border);
}

.plan-card-name {
  font-size: 17.5px;
  font-weight: 700;
  margin: 0 0 2px;
  text-align: center;
  color: var(--text);
}

.plan-card-term {
  display: block;
  text-align: center;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-subtle);
}

.plan-card-price {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 5px;
  margin-top: 12px;
  font-family: var(--font-num);
}
.plan-card-price .amount {
  font-size: 42px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.03em;
  color: var(--text);
}
.plan-card-hero .plan-card-price .amount {
  font-size: 46px;
  color: var(--vip-strong);
}
.plan-card-price .unit {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-muted);
}

/* Value Props in Cards */
.plan-card-value {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 66px;
  margin-top: 6px;
  text-align: center;
  gap: 3px;
}

.plan-monthly-rate {
  font-size: 14px;
  font-weight: 700;
  color: var(--vip-strong);
  line-height: 1.35;
}

.plan-savings-pill {
  display: inline-flex;
  align-items: center;
  font-size: 11.5px;
  font-weight: 700;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--vip-soft);
  color: var(--vip-strong);
  border: 1px solid var(--vip-border);
  line-height: 1.35;
}

.plan-daily-rate {
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.35;
}

.plan-character-desc {
  font-size: 13px;
  color: var(--text-muted);
  line-height: 1.5;
  text-align: center;
  min-height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 10px 0 12px;
  padding-block: 8px;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}

.plan-benefit-list {
  list-style: none;
  padding: 0;
  margin: 0 0 18px;
  display: grid;
  gap: 9px;
}
.plan-benefit-list li {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--text);
}
.plan-benefit-list li .icon {
  color: var(--success);
  flex: 0 0 auto;
  margin-top: 2px;
}

.plan-card-action {
  margin-top: auto;
}
.plan-card-action .btn {
  min-height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-weight: 600;
  font-size: 14.5px;
}

/* Desktop only: overlay the 3 pricing cards on the empty right-hand area of
   the hero background image.
   Horizontal room is tight — the mascot's rightmost point (paw + book) sits at
   ~47.9% of the image width, so the card group's left edge is pinned just past
   it with a deliberately thin safety margin; width can only grow by reclaiming
   the outer right margin. Vertical room is not constrained by the mascot at all
   (it never reaches this half of the image), so cards are given generous
   padding/font sizes and simply grow taller within the centered column instead. */
@media (min-width: 961px) {
  .vip-hero-cards {
    position: absolute;
    top: 50%;
    right: 2%;
    transform: translateY(-50%);
    width: 49%;
    gap: 1.4%;
    margin-bottom: 0;
    padding-top: 0;
  }
  .vip-hero-cards .plan-card {
    padding: 18px 15px 16px;
    border-radius: 14px;
  }
  .vip-hero-cards .plan-card .plan-badge {
    top: -10px;
    font-size: 10px;
    padding: 3.5px 11px;
  }
  .vip-hero-cards .plan-card-name { font-size: 14.5px; margin-top: 9px; margin-bottom: 0; }
  .vip-hero-cards .plan-card-term { font-size: 10.5px; margin-top: 2px; }
  .vip-hero-cards .plan-card-price { margin-top: 10px; gap: 4px; }
  .vip-hero-cards .plan-card-price .amount { font-size: 26px; }
  .vip-hero-cards .plan-card-hero .plan-card-price .amount { font-size: 29px; }
  .vip-hero-cards .plan-card-price .unit { font-size: 9.5px; }
  .vip-hero-cards .plan-card-value { min-height: auto; margin-top: 6px; gap: 3px; }
  .vip-hero-cards .plan-monthly-rate { font-size: 11px; }
  .vip-hero-cards .plan-savings-pill { font-size: 8.5px; padding: 3px 8px; white-space: normal; text-align: center; line-height: 1.35; }
  .vip-hero-cards .plan-daily-rate { font-size: 9.5px; }
  /* One redundant micro-line per card (already restated elsewhere) is hidden
     to make room for larger type — no package data or benefit is removed. */
  .vip-hero-cards .plan-card-value span:last-child { display: none; }
  .vip-hero-cards .plan-character-desc { display: none; }
  .vip-hero-cards .plan-benefit-list { gap: 6px; margin: 10px 0 12px; }
  .vip-hero-cards .plan-benefit-list li { font-size: 11px; gap: 6px; }
  .vip-hero-cards .plan-benefit-list li .icon { width: 13px; height: 13px; }
  .vip-hero-cards .plan-card-action .btn {
    min-height: 40px;
    font-size: 12.5px;
    font-weight: 700;
    padding: 0 8px;
  }
}

/* Trust Bar */
.trust-bar {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 16px 22px;
  align-items: center;
  margin-bottom: 20px;
}
.trust-bar-item {
  display: flex;
  align-items: center;
  gap: 12px;
}
.trust-bar-item .icon {
  color: var(--primary);
  flex: 0 0 auto;
}
.trust-bar-item h3 {
  font-size: 14px;
  font-weight: 700;
  margin: 0;
  color: var(--text);
  line-height: 1.35;
}
.trust-bar-item p {
  font-size: 12px;
  color: var(--text-muted);
  margin: 2px 0 0;
  line-height: 1.4;
}

/* FAQ Accordion */
.faq-accordion-group {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 24px;
}
.faq-accordion {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.faq-accordion:hover {
  border-color: var(--primary-border);
}
.faq-accordion[open] {
  border-color: var(--primary-border);
  box-shadow: var(--shadow-xs);
}
.faq-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 15px 18px;
  min-height: 50px;
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  cursor: pointer;
  user-select: none;
  list-style: none;
}
.faq-summary::-webkit-details-marker {
  display: none;
}
.faq-summary:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: -3px;
}
.faq-icon {
  flex: 0 0 auto;
  color: var(--text-muted);
  display: inline-flex;
  transition: transform var(--t-fast);
}
.faq-accordion[open] .faq-icon {
  transform: rotate(180deg);
  color: var(--primary);
}
.faq-content {
  padding: 0 18px 16px;
  border-top: 1px solid var(--border);
}
.faq-content p {
  font-size: 13.5px;
  color: var(--text-muted);
  margin: 10px 0 0;
  line-height: 1.65;
}

/* Responsive Breakpoints */
@media (max-width: 960px) {
  .plan-grid-trio {
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
  }
  .plan-card {
    padding: 24px 14px 18px;
  }
  .plan-card-price .amount {
    font-size: 34px;
  }
  .plan-card-hero .plan-card-price .amount {
    font-size: 38px;
  }
  .trust-bar {
    grid-template-columns: 1fr;
    gap: 12px;
    padding: 14px 18px;
  }
}

@media (max-width: 760px) {
  .plan-grid-trio {
    grid-template-columns: 1fr;
    max-width: 420px;
    margin-inline: auto;
    gap: 18px;
  }
  /* Mobile Priority Order: 365 Days first! */
  .plan-card-hero {
    order: 1;
  }
  .plan-card-popular {
    order: 2;
  }
  .plan-card-trial {
    order: 3;
  }
}


/* The reader's current membership state, above the plans. */
.vip-status {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space); flex-wrap: wrap;
  border-color: var(--vip-border); background: var(--vip-soft);
}
.vip-status .who { display: flex; align-items: center; gap: 14px; min-width: 0; }
.vip-status h2, .vip-status h3 { font-size: 16.5px; margin: 0 0 3px; color: var(--vip-strong); }
.vip-status p { font-size: 13.5px; color: var(--text-muted); margin: 0; }

/* The upsell shown where VIP content is locked — the exam and mock listings,
   an individual locked set, the member dashboard. One component, so the offer
   looks the same everywhere the reader meets it. */
.vip-panel {
  border: 1px solid var(--vip-border); border-radius: var(--radius-lg);
  background: var(--vip-soft); padding: var(--space-md);
  display: flex; align-items: center; gap: var(--space);
  flex-wrap: wrap;
}
.vip-panel-center { flex-direction: column; text-align: center; }
.vip-panel .body { flex: 1 1 260px; min-width: 0; }
.vip-panel h2, .vip-panel h3 { font-size: 17px; margin: 0 0 4px; color: var(--vip-strong); }
.vip-panel p { font-size: 13.5px; color: var(--text-muted); margin: 0; line-height: 1.65; }
.vip-panel .actions { flex: 0 0 auto; display: flex; gap: 9px; flex-wrap: wrap; }
/* Stacked, the flex basis above would be read as a 260px minimum height and
   leave a hole between the copy and the button. */
.vip-panel-center .actions,
.vip-panel-center .body { width: 100%; flex: 0 1 auto; }

/* The gold square that carries the crown beside a membership message. */
.vip-mark {
  width: 46px; height: 46px; flex: 0 0 auto; border-radius: var(--radius);
  display: grid; place-items: center;
  background: var(--vip-gradient); color: var(--vip-on);
}
.vip-mark-lg { width: 58px; height: 58px; border-radius: var(--radius-lg); }

/* A question and its answer. The question keeps the body's text colour and the
   answer steps back, which is the only hierarchy a three-item FAQ needs. */
.faq-item h3 { font-size: 15.5px; margin: 0 0 6px; }
.faq-item p { font-size: 14px; color: var(--text-muted); margin: 0; line-height: 1.75; }

/* Three short reassurances about paying. Text-led, with the icon as a small
   mark above the line rather than a coloured tile, so this reads as a note and
   does not compete with the plans it sits under. */
.assurances { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--space-md); }
.assurance { display: grid; gap: 4px; justify-items: center; text-align: center; }
.assurance .icon { color: var(--primary); margin-bottom: 4px; }
.assurance h3 { font-size: 15px; margin: 0; }
.assurance p { font-size: 13px; color: var(--text-muted); margin: 0; line-height: 1.6; max-width: 34ch; }

/* Plan comparison — the free/VIP table shared by the home page and the
   packages page. The VIP column is tinted end to end so the eye can follow one
   plan down the table, and every yes/no is an icon plus a word rather than an
   emoji, so it keeps its meaning in both palettes. */
.plan-compare { border-color: var(--vip-border); overflow: hidden; }
.plan-compare .card-head { background: var(--vip-soft); border-bottom-color: var(--vip-border); }
.plan-compare .card-head h2,
.plan-compare .card-head h3 { display: flex; align-items: center; gap: 8px; font-size: 17px; color: var(--vip-strong); }
/* The minimum keeps the three columns readable on a phone; below it the table
   scrolls sideways inside .table-wrap rather than squeezing each cell into a
   two-word-per-line column. */
.plan-compare table { margin: 0; font-size: 13.5px; min-width: 560px; }
/* Seven single-line rows, so the whole promise is one glance beside the two
   prices. Anything that needed a second line of explanation belongs on the
   packages page, not in the comparison. */
.plan-compare th, .plan-compare td { padding: 12px 16px; vertical-align: middle; text-align: left; }
.plan-compare .col-plan { text-align: center; width: 26%; }
.plan-compare .col-vip { text-align: center; width: 30%; background: color-mix(in srgb, var(--vip-soft) 70%, var(--surface)); }
.plan-compare tbody .col-vip { background: color-mix(in srgb, var(--vip-soft) 38%, var(--surface)); }
.plan-compare th.col-vip { color: var(--vip-strong); }
.plan-compare thead th { font-size: 13px; background: var(--vip-soft); }
.plan-compare thead th:first-child { color: var(--vip-strong); }
/* The row header is a label, not a column heading — it keeps the body surface. */
.plan-compare tbody th { background: transparent; white-space: normal; font-weight: 400; }
.plan-compare tbody tr + tr th,
.plan-compare tbody tr + tr td { border-top: 1px solid var(--border); }
.plan-compare .mode {
  display: flex; align-items: center; gap: 11px;
  font-weight: 600; font-size: 13.5px; color: var(--text); line-height: 1.4;
}
.plan-compare .mode .ic {
  width: 30px; height: 30px; flex: 0 0 auto; border-radius: 8px;
  display: grid; place-items: center;
  background: var(--primary-soft); color: var(--primary);
}
.plan-compare .yes,
.plan-compare .no {
  display: inline-flex; align-items: center; gap: 6px;
  font-weight: 600; font-size: 13px;
}
.plan-compare .yes { color: var(--success); }
.plan-compare .yes-vip { color: var(--vip); font-weight: 700; }
.plan-compare .no { color: var(--text-muted); font-weight: 500; }
.plan-compare .no .icon { opacity: .7; }

/* The home page's membership block: what the two plans may reach on the left,
   and what the two most-taken plans cost on the right. The full four-plan grid
   stays on the packages page — the home page's job is to make the offer
   legible, not to close the sale. */
/* The comparison table sets a 620px minimum so its cells stay readable, and a
   grid track sizes to its content's minimum unless told otherwise — so without
   `min-width: 0` the track grew past the viewport on a phone and the table
   scrolled the page instead of scrolling inside its own wrapper. */
.vip-showcase { display: grid; grid-template-columns: minmax(0, 1.12fr) minmax(0, .95fr); gap: var(--space-md); align-items: stretch; }
.vip-showcase > * { min-width: 0; display: flex; flex-direction: column; }
.price-pair { width: 100%; display: grid; grid-template-columns: 1fr 1fr; gap: 18px; padding-top: 13px; align-items: stretch; }
/* Three terms rather than two. The extra card is paid for by a wider price
   column and a tighter scale inside every card, so the section keeps its
   height and the comparison table keeps enough room to stay readable. */
.vip-showcase.has-trio { grid-template-columns: minmax(0, 1fr) minmax(0, 1.14fr); }
.price-pair.is-trio { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 11px; flex: 1 1 auto; }
/* The cards take their height from the row rather than carrying their own, so
   the trio finishes on exactly the same line as the comparison table beside
   it however many rows that table has. */
.is-trio .price-card-wrap { height: 100%; }
/* Whichever side is taller sets the row: the table stretches to the cards when
   the copy runs long, and the cards stretch to the table when it does not, so
   the two columns always finish on the same line. */
.vip-showcase.has-trio .plan-compare { flex: 1 1 auto; display: flex; flex-direction: column; }
/* When the cards are the taller side, the table takes up the difference across
   its rows rather than leaving one blank strip under the last one. */
.vip-showcase.has-trio .plan-compare .table-wrap { flex: 1 1 auto; }
.vip-showcase.has-trio .plan-compare table { height: 100%; }
.is-trio .price-card-wrap .price-mini { flex: 1 1 auto; height: 100%; min-height: 0; }
.is-trio .price-mini { padding: 22px 12px 18px; }
.is-trio .price-mini .amount { font-size: 33px; }
.is-trio .price-mini .amount .unit { font-size: 12px; }
.is-trio .price-mini .name { font-size: 13px; }
.is-trio .price-mini ul { margin: 16px 0 20px; gap: 10px; font-size: 12.5px; }
.is-trio .price-icon { width: 46px; height: 46px; margin-bottom: 8px; }
.price-mini {
  position: relative; display: flex; flex-direction: column; text-align: center;
  padding: 26px 18px 22px; border-radius: var(--radius-lg);
}
.price-mini .name { font-size: 14px; font-weight: 600; color: var(--text-muted); }
.price-mini .amount {
  font-family: var(--font-num); font-size: 42px; font-weight: 800;
  letter-spacing: -.035em; line-height: 1.05; margin-top: 10px;
}
.price-mini .amount .unit {
  display: block; font-size: 13px; font-weight: 600;
  color: var(--text-muted); letter-spacing: 0; margin-top: 4px;
  font-family: var(--font);
}
.plan-value-stats {
  margin-top: 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  min-height: 72px;
  justify-content: center;
}
.plan-stat-highlight {
  font-size: 13px;
  font-weight: 700;
  color: var(--primary-dark);
  line-height: 1.35;
}
.plan-pay-term {
  font-size: 11px;
  color: var(--text-muted);
  line-height: 1.35;
}
.price-mini ul {
  list-style: none; padding: 0; margin: 16px 0 22px;
  display: grid; gap: 12px; text-align: left; font-size: 12.5px; line-height: 1.45;
}
.price-mini li { display: flex; align-items: flex-start; gap: 8px; }
.price-mini li .icon { color: var(--success); flex: 0 0 auto; margin-top: 1px; }
/* Key terms on the year plan set in bold */
.price-mini li b { font-weight: 700; }
.price-mini.is-hero li b { color: #fff; }
.plan-card-action { margin-top: auto; display: flex; flex-direction: column; align-items: stretch; }
.plan-sub-cta {
  display: block; text-align: center; margin-top: 8px;
  font-size: 11.5px; font-weight: 600; color: var(--text-muted); line-height: 1.35;
}

/* The recommended plan inverts to deep blue with a gold action: it is the one
   moment of contrast in the section, which is cheaper than making the card
   bigger and breaking the pair. */
.price-mini.is-hero {
  background: linear-gradient(165deg, #12275e 0%, #0d1c46 60%, #0a1430 100%);
  border-color: transparent; color: #fff;
  box-shadow: 0 12px 26px rgba(10, 20, 48, .24);
}
.price-mini.is-hero .name { color: #c3d1ee; }
.price-mini.is-hero .amount { color: #fff; }
.price-mini.is-hero .amount .unit { color: var(--navy-dim); }
.price-mini.is-hero .plan-stat-highlight { color: #ffd666; font-size: 13.5px; }
.price-mini.is-hero .plan-pay-term { color: #c3d5fc; }
.price-mini.is-hero li { color: #e6ecfa; }
.price-mini.is-hero li .icon { color: #6fe3a3; }
.price-mini.is-hero .plan-badge { top: -13px; }
.price-mini.is-hero .plan-sub-cta.is-hero { color: #d6e4ff; font-size: 12.5px; font-weight: 700; }
/* On a dark page "navy" is no longer a contrast — it is merely darker than the
   card beside it. The highlight becomes a brand tint instead, which still reads
   as the picked plan. */
:root[data-theme="dark"] .price-mini.is-hero {
  background: linear-gradient(180deg, color-mix(in srgb, var(--primary) 26%, var(--surface)), var(--surface));
  border-color: var(--primary-border);
}
:root[data-theme="dark"] .plan-compare tbody .col-vip {
  background: color-mix(in srgb, var(--vip-soft) 12%, var(--surface));
}
:root[data-theme="dark"] .price-mini.is-hero .plan-stat-highlight {
  color: #fbbf24;
}
:root[data-theme="dark"] .price-mini.is-hero .plan-pay-term {
  color: var(--text-muted);
}
:root[data-theme="dark"] .price-mini.is-hero .plan-sub-cta.is-hero {
  color: #93c5fd;
}

/* 404 / 403 / 500. The status number is evidence, not decoration, so it sits
   under the icon at a readable size instead of behind the heading as a giant
   ghosted numeral. */
.error-page .error-mark {
  width: 58px; height: 58px; margin: 0 auto var(--space);
  display: grid; place-items: center; border-radius: var(--radius-lg);
  background: var(--primary-soft); color: var(--primary);
  border: 1px solid var(--primary-border);
}
.error-page .error-code {
  font-size: 13px; font-weight: 700; letter-spacing: .12em;
  color: var(--text-subtle); margin-bottom: 6px;
}
.error-page h1 { font-size: clamp(24px, 3.6vw, 32px); margin: 0 0 10px; }
.error-page .lead { color: var(--text-muted); max-width: 48ch; margin: 0 auto var(--space-md); }

/* Sign-in, registration, password reset. These pages carry a single card on an
   otherwise empty screen, which read as unfinished; the tinted band behind them
   gives the card something to sit on, and the card itself is raised. */
.auth-page {
  padding: var(--space-xl) 0 var(--space-2xl);
  background:
    radial-gradient(760px 380px at 50% -8%, color-mix(in srgb, var(--primary) 13%, transparent), transparent 62%),
    var(--background);
}
.auth-box { width: 100%; max-width: 460px; margin: 0 auto; }
.auth-box .card { padding: var(--space-md); }
.auth-head { text-align: center; margin-bottom: var(--space-md); }
.auth-head h1 { font-size: 25px; margin: 0 0 5px; }
.auth-head p { color: var(--text-muted); font-size: 14.5px; margin: 0; }
.auth-foot { text-align: center; font-size: 14px; color: var(--text-muted); margin: var(--space) 0 0; }
.auth-note { text-align: center; font-size: 13px; color: var(--text-subtle); margin-top: var(--space); }

/* What an account is worth, listed beside the registration form. */
.benefit { display: flex; align-items: flex-start; gap: 12px; }
.benefit .cat-icon { width: 38px; height: 38px; }
.benefit b { display: block; font-size: 14.5px; }
.benefit span > span { font-size: 13.5px; color: var(--text-muted); line-height: 1.6; }

/* "or sign in with an email address" — a label centred on a rule. */
.or-sep {
  display: flex; align-items: center; gap: 12px;
  margin: var(--space) 0; color: var(--text-subtle); font-size: 13px;
}
.or-sep::before, .or-sep::after { content: ''; flex: 1 1 auto; height: 1px; background: var(--border); }

/* Checkout. The amount is the first thing the payer needs to match against
   their banking app, so it leads. */
.pay-amount {
  background: var(--surface-muted); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 12px; margin-bottom: 18px;
}
.pay-amount .k { display: block; font-size: 13px; color: var(--text-muted); margin-bottom: 2px; }
.pay-amount .v { font-family: var(--font-num); font-size: 32px; font-weight: 800; color: var(--primary); line-height: 1; }
.pay-amount .v span { font-size: 16px; font-weight: 600; }
.pay-amount .sub { display: block; font-size: 12.5px; color: var(--text-muted); margin-top: 5px; }

/* The PromptPay slip. Fixed light colours on purpose and in both palettes: a
   QR code has to stay dark-on-white to scan, and the Thai QR header is a
   scheme mark, not a themeable surface. */
.qr-slip {
  background: #fff; border: 1px solid rgba(0, 0, 0, .1);
  border-radius: var(--radius-lg); box-shadow: 0 4px 16px rgba(0, 0, 0, .1);
  padding: 18px 16px 14px; max-width: 320px; width: 100%;
  margin: 0 auto 16px; display: inline-block;
}
.qr-slip .scheme {
  background: #003b6d; color: #fff; border-radius: 10px;
  padding: 8px 12px; margin-bottom: 12px;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  font-weight: 800; letter-spacing: .5px; font-size: 14px;
}
.qr-slip .scheme i { background: #fff; color: #003b6d; font-size: 10.5px; font-weight: 700; padding: 2px 6px; border-radius: 4px; font-style: normal; }
.qr-slip img { width: 230px; height: 230px; display: block; margin: 0 auto; border-radius: 8px; }
.qr-slip .payee { margin-top: 12px; padding-top: 10px; border-top: 1px dashed #e2e8f0; text-align: center; }
.qr-slip .payee .k { font-size: 12px; color: #64748b; }
.qr-slip .payee .n { font-size: 16px; font-weight: 700; color: #0f172a; }
.qr-slip .payee .b { font-size: 12px; color: #64748b; margin-top: 2px; }

/* "waiting for payment" — a live state, so it spins. */
.pay-watch {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  padding: 10px; border-radius: var(--radius-sm);
  background: var(--primary-soft); color: var(--primary-dark);
  font-size: 13.5px; font-weight: 600;
}
.pay-watch .spinner {
  width: 16px; height: 16px; flex: 0 0 auto;
  border: 2px solid currentColor; border-top-color: transparent;
  border-radius: 50%; animation: spin 1s linear infinite;
}
/* The poller swaps to this class once the bank confirms. */
.pay-watch.is-paid { background: var(--success-soft); color: var(--success); }

/* A panel's own heading, used inside a card that is not a full section. */
.panel-title { display: flex; align-items: center; gap: 8px; font-size: 16px; margin: 0 0 12px; }

/* A numbered procedure. */
.steps { padding-left: 20px; margin: 0; font-size: 13.5px; line-height: 1.9; color: var(--text-muted); }
.steps li::marker { color: var(--primary); font-weight: 700; }
.steps b { color: var(--text); }

/* Manual payment confirmation. The operating hours lead the upload decision,
   while the file control remains a real native input for validation and
   keyboard access. */
.payment-upload-card { border-color: var(--primary-border); box-shadow: var(--shadow); }
.service-hours {
  display: flex; align-items: flex-start; gap: 12px; padding: 15px;
  border: 1px solid var(--primary-border); border-radius: var(--radius);
  background: var(--primary-soft);
}
.service-hours-icon {
  width: 42px; height: 42px; flex: 0 0 auto; display: grid; place-items: center;
  border-radius: 50%; color: var(--primary); background: var(--surface-raised);
  border: 1px solid var(--primary-border);
}
.service-hours-body { min-width: 0; }
.service-hours-label {
  display: block; color: var(--text-muted); font-size: 12px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
}
/* The promise, not the opening hours, is the loudest line in the card. */
.service-hours-sla {
  display: block; margin-top: 3px; color: var(--primary-dark); font-size: clamp(19px, 3.2vw, 24px);
  font-weight: 800; line-height: 1.3; letter-spacing: -.01em;
}
.service-hours-time { display: block; margin-top: 5px; color: var(--text-muted); font-size: 13px; }
.service-hours-time b { color: var(--text); font-weight: 700; }
.service-hours p { margin: 7px 0 0; color: var(--text-muted); font-size: 12.5px; line-height: 1.55; }
.service-hours-after { margin: 9px 2px 20px; color: var(--text-muted); font-size: 12.5px; line-height: 1.55; }
/* Under the QR, in a centred card: the promise stays left-read and one step
   quieter than the amount and the code above it. */
.service-hours-qr { margin-top: 16px; padding: 14px; text-align: left; }
.service-hours-qr .service-hours-sla { font-size: clamp(17px, 2.6vw, 20px); }
.service-hours-qr p { font-size: 12px; }
.service-hours-qr .service-hours-after { margin: 6px 0 0; font-size: 12px; }
.payment-upload-heading { display: flex; align-items: flex-start; gap: 11px; margin-bottom: 14px; }
.payment-upload-heading-icon {
  width: 38px; height: 38px; flex: 0 0 auto; display: grid; place-items: center;
  color: var(--primary); background: var(--primary-soft); border-radius: var(--radius-sm);
}
.payment-upload-heading h2 { margin: 0 0 4px; font-size: 18px; }
.payment-upload-heading p { margin: 0; color: var(--text-muted); font-size: 13px; line-height: 1.6; }
.payment-upload-form { margin: 0; }
.payment-upload-dropzone {
  position: relative; display: flex; min-height: 156px; padding: 22px 16px;
  flex-direction: column; align-items: center; justify-content: center; text-align: center;
  border: 1.5px dashed var(--border-strong); border-radius: var(--radius);
  background: var(--surface-muted); cursor: pointer;
  transition: border-color var(--t), background var(--t), box-shadow var(--t);
}
.payment-upload-dropzone:hover { border-color: var(--primary); background: var(--primary-soft); }
.payment-upload-dropzone:focus-within { box-shadow: 0 0 0 3px var(--primary-soft); border-color: var(--primary); }
.payment-upload-dropzone.is-selected { border-style: solid; border-color: var(--success); background: var(--success-soft); }
.payment-upload-dropzone input {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.payment-upload-icon {
  width: 48px; height: 48px; display: grid; place-items: center; margin-bottom: 9px;
  border-radius: 50%; color: var(--primary); background: var(--surface-raised); border: 1px solid var(--border);
}
.payment-upload-dropzone.is-selected .payment-upload-icon { color: var(--success); border-color: var(--success-border); }
.payment-upload-prompt { color: var(--text); font-size: 14.5px; font-weight: 700; }
.payment-upload-formats { margin-top: 3px; color: var(--text-muted); font-size: 12px; }
.payment-upload-filename {
  display: block; max-width: 100%; margin-top: 9px; color: var(--text-subtle); font-size: 12.5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.payment-upload-dropzone.is-selected .payment-upload-filename { color: var(--success); font-weight: 700; }
.payment-upload-submit { min-height: 48px; margin-top: 12px; font-size: 14.5px; }
.payment-upload-submit.is-loading { cursor: wait; }
.payment-upload-submit .spinner {
  width: 16px; height: 16px; display: inline-block; border: 2px solid currentColor;
  border-top-color: transparent; border-radius: 50%; animation: spin 1s linear infinite;
}
.payment-trust-list {
  display: grid; gap: 7px; margin: 14px 0 0; padding: 14px 0 0; list-style: none;
  border-top: 1px solid var(--border); color: var(--text-muted); font-size: 12.5px;
}
.payment-trust-list li { display: flex; align-items: flex-start; gap: 7px; }
.payment-trust-list .icon { flex: 0 0 auto; margin-top: 2px; color: var(--success); }
/* ---------------------------------------- The order is paid and being checked
   A confirmation, not a payment screen. The page keeps a comfortable measure
   rather than the full desktop container (the wide .container rule at 1200px
   would otherwise stretch four short paragraphs across 1400px and leave the
   right half of the screen empty), and the content divides into what is
   happening and what was bought. Only the summary is a card: one border on
   the screen instead of a card inside a card inside a card. */
.checkout-review-shell { max-width: 1060px; }
@media (min-width: 1200px) { .checkout-review-shell { max-width: 1060px; } }

.review-layout {
  display: grid; align-items: start; gap: var(--space-md);
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  margin-bottom: var(--space-md);
}
.review-main { min-width: 0; }
.review-mark {
  width: 50px; height: 50px; display: grid; place-items: center; margin-bottom: 14px;
  color: var(--success); background: var(--success-soft); border-radius: 50%;
}
.review-main h2 { margin: 6px 0 4px; font-size: clamp(24px, 3.4vw, 31px); letter-spacing: -.02em; }
.review-lead { margin: 0 0 18px; color: var(--text); font-size: 15.5px; line-height: 1.6; }
.review-note { margin: 0 0 10px; color: var(--text-muted); font-size: 13px; line-height: 1.65; }
.review-note b { color: var(--text); }

/* The promise, stated once. Tinted rather than boxed, so it reads as an
   emphasised line of the message and not as another panel. */
.review-sla {
  display: flex; align-items: flex-start; gap: 13px;
  padding: 15px 16px; margin: 0 0 14px;
  background: var(--primary-soft); border-radius: var(--radius);
  border-left: 3px solid var(--primary);
}
.review-sla-icon { flex: 0 0 auto; display: grid; place-items: center; margin-top: 2px; color: var(--primary); }
.review-sla-label {
  display: block; color: var(--text-muted); font-size: 11.5px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
}
.review-sla-value {
  display: block; margin-top: 3px; color: var(--primary-dark);
  font-size: clamp(18px, 2.4vw, 21px); font-weight: 800; line-height: 1.35;
}
.review-sla-hours { display: block; margin-top: 4px; color: var(--text-muted); font-size: 13px; }
.review-sla-hours b { color: var(--text); font-weight: 700; }

.review-summary { position: sticky; top: calc(var(--header-h) + 16px); }
.review-summary-title {
  margin: 0 0 4px; padding-bottom: 12px; font-size: 15px;
  border-bottom: 1px solid var(--border);
}
.review-summary-list { margin: 0; }
.review-summary-list > div {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--space); padding: 11px 0; border-bottom: 1px solid var(--border);
}
.review-summary-list > div:last-child { border-bottom: 0; }
.review-summary-list dt { color: var(--text-muted); font-size: 13px; }
.review-summary-list dd { margin: 0; font-weight: 600; font-size: 13.5px; text-align: right; }
.review-summary-amount { font-size: 17px; font-weight: 800; color: var(--text); }
.review-summary-actions { display: grid; gap: 9px; margin-top: var(--space); }
.review-summary-actions .btn { width: 100%; justify-content: center; min-height: 46px; }

/* Tablet: the two columns still fit, but the summary is narrow enough that a
   label and its value can no longer share a line without one of them
   wrapping mid-word. They stack instead of squeezing. */
@media (min-width: 768px) and (max-width: 1023px) {
  .review-layout { gap: var(--space); grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); }
  .review-summary-list > div { flex-direction: column; align-items: flex-start; gap: 3px; padding: 10px 0; }
  .review-summary-list dd { text-align: left; }
}
@media (max-width: 767px) {
  .review-layout { grid-template-columns: minmax(0, 1fr); }
  .review-summary { position: static; }
}

@media (max-width: 575px) {
  .payment-upload-card { padding: 18px; }
  .service-hours { padding: 13px; }
  .service-hours-icon { width: 38px; height: 38px; }
  .service-hours-sla { font-size: 19px; }
  .payment-upload-dropzone { min-height: 146px; }
  .review-mark { width: 44px; height: 44px; }
  .review-sla { padding: 13px 14px; }
}

/* The local payment simulator. Dashed, so it never reads as a real control. */
.test-panel { border-style: dashed; border-color: var(--warning-border); background: var(--warning-soft); }
.test-panel .test-title { display: inline-flex; align-items: center; gap: 6px; font-weight: 700; font-size: 13px; color: var(--warning); }

/* Payment confirmation. A receipt, not a celebration: the outcome is stated
   once at the top and the rest is the record of what was bought. */
.receipt-card { padding: var(--space-xl) var(--space-md); }
.receipt-card h1 { font-size: clamp(22px, 3.6vw, 29px); margin: 0 0 8px; }
.receipt-card .lead { color: var(--text-muted); max-width: 50ch; margin: 0 auto var(--space-md); font-size: 15px; }
.receipt-mark {
  width: 66px; height: 66px; border-radius: 50%; margin-bottom: var(--space);
  display: inline-grid; place-items: center;
  background: var(--success-soft); color: var(--success);
  border: 1px solid var(--success-border);
}
.receipt {
  max-width: 440px; margin: 0 auto var(--space-md); padding: var(--space);
  background: var(--surface-muted); border: 1px solid var(--border);
  border-radius: var(--radius); text-align: left; font-size: 14px;
}
.receipt > div { display: flex; align-items: center; justify-content: space-between; gap: var(--space); }
.receipt > div + div { margin-top: 10px; }
.receipt dt { color: var(--text-muted); }
.receipt dd { margin: 0; font-weight: 600; text-align: right; }
.receipt dd.amount { color: var(--primary); font-size: 16px; font-weight: 700; }
.receipt .total { border-top: 1px dashed var(--border-strong); padding-top: 10px; }

/* Stored article HTML. Limited to the tags the sanitiser actually allows, and
   kept here rather than in a <style> block on the article page so the prose
   shares the same tokens as everything else. */
.article-body { font-size: 17px; line-height: 1.9; color: var(--text); }
.article-body > * + * { margin-top: 1.15em; }
.article-body h2 { font-size: 24px; margin-top: 1.9em; letter-spacing: -.02em; }
.article-body h3 { font-size: 19px; margin-top: 1.6em; }
.article-body ul, .article-body ol { padding-left: 1.4em; }
.article-body li + li { margin-top: .5em; }
.article-body li::marker { color: var(--primary); }
.article-body blockquote {
  margin-left: 0; padding: 14px 20px;
  border-left: 3px solid var(--primary); background: var(--surface-muted);
  border-radius: 0 var(--radius) var(--radius) 0; color: var(--text-muted);
  font-size: 16.5px;
}
.article-body img { border-radius: var(--radius); border: 1px solid var(--border); }
.article-body code { background: var(--surface-muted); padding: 2px 6px; border-radius: 5px; }
.article-body pre { background: var(--surface-muted); padding: 14px; border-radius: var(--radius); overflow-x: auto; }
.article-body table { width: 100%; border-collapse: collapse; font-size: 15px; }
.article-body th, .article-body td { padding: 10px 13px; border: 1px solid var(--border); text-align: left; }
.article-body th { background: var(--surface-muted); font-weight: 600; }

/* Streak chip */
.streak-chip {
  display: inline-flex; align-items: center; gap: 7px; padding: 6px 13px;
  background: var(--warning-soft); color: var(--warning);
  border: 1px solid var(--warning-border); border-radius: var(--radius-pill);
  font-size: 13.5px; font-weight: 700;
}
.streak-chip-sm { padding: 2px 10px; font-size: 12.5px; }

/* The member dashboard's own name heading, beside the avatar. */
.member-name { font-size: clamp(21px, 3vw, 27px); margin: 0; letter-spacing: -.015em; }

/* ----------------------------------------------- HOME MOCK EXAM SECTION (PREMIUM) */
.home-fields-section {
  padding: 44px 0 28px;
  background: transparent;
}

.home-mock-container {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  background: linear-gradient(145deg, #f8fbff 0%, #f1f6fe 48%, #f7faff 100%);
  border: 1px solid rgba(219, 230, 246, 0.95);
  border-radius: 30px;
  padding: 52px 48px 42px;
  box-shadow: 0 10px 30px -10px rgba(15, 23, 42, 0.04), 0 20px 40px -15px rgba(37, 99, 235, 0.04);
}

/* Decorative background glow & contour rings */
.home-mock-decor {
  position: absolute;
  top: 0;
  right: 0;
  width: 580px;
  height: 100%;
  pointer-events: none;
  overflow: hidden;
  z-index: 0;
}

.home-mock-glow {
  position: absolute;
  top: -12%;
  right: 6%;
  width: 460px;
  height: 400px;
  background: radial-gradient(circle, rgba(219, 234, 254, 0.55) 0%, rgba(240, 246, 255, 0) 70%);
  pointer-events: none;
}

.home-mock-rings {
  position: absolute;
  top: -50px;
  right: -50px;
  width: 580px;
  height: 580px;
  pointer-events: none;
}

/* Top Area: 2 columns */
.home-mock-top {
  display: grid;
  grid-template-columns: minmax(0, 1.48fr) minmax(0, 1fr);
  align-items: center;
  gap: 36px;
  position: relative;
  z-index: 1;
}

.home-mock-left {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* Pill badge */
.home-mock-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: #eef5ff;
  border: 1px solid #c7dcfb;
  color: #1d4ed8;
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 7px 16px;
  border-radius: 999px;
  margin-bottom: 22px;
  box-shadow: 0 1px 3px rgba(37, 99, 235, 0.06);
}

.home-mock-badge-ic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #1d4ed8;
}

/* Headline */
.home-mock-title {
  font-size: clamp(34px, 4.2vw, 56px);
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -0.025em;
  color: #0b152d;
  margin: 0 0 16px;
}

.home-mock-title span {
  display: inline-block;
}

.home-mock-title-accent {
  color: #165dfc;
}

/* Description */
.home-mock-desc {
  font-size: clamp(15.5px, 1.2vw, 18px);
  color: #56637f;
  line-height: 1.65;
  max-width: 580px;
  margin: 0;
}

/* Hero Illustration right */
.home-mock-right {
  display: flex;
  justify-content: flex-end;
  align-items: center;
}

.home-mock-illu-wrap {
  max-width: 380px;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}

.home-mock-illu-img {
  width: 100%;
  height: auto;
  max-height: 290px;
  object-fit: contain;
  display: block;
  filter: drop-shadow(0 14px 28px rgba(30, 58, 138, 0.08));
  user-select: none;
}

/* Database-driven grid: three cards balance across desktop; future cards wrap
   without a caller having to pick a new layout class. */
.home-mock-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 22px;
  margin-top: 40px;
  position: relative;
  z-index: 1;
}

.home-mock-card {
  background: #ffffff;
  border: 1px solid #e2e8f0;
  border-radius: 24px;
  padding: 28px 24px 24px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: inherit;
  text-decoration: none;
  box-shadow: 0 4px 16px rgba(15, 23, 42, 0.03);
  transition: transform 0.22s var(--ease), box-shadow 0.22s var(--ease), border-color 0.22s var(--ease);
  position: relative;
  min-width: 0;
  text-align: center;
}

.home-mock-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 16px 36px -8px rgba(15, 23, 42, 0.1);
  text-decoration: none;
  color: inherit;
}

.home-mock-card:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 3px;
}

.home-mock-card-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex-grow: 1;
}

.home-mock-card-icon {
  width: 78px;
  height: 78px;
  border-radius: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 22px;
  flex-shrink: 0;
}

.home-mock-card-icon svg {
  stroke-width: 2.1px;
}

.home-mock-card-title {
  font-size: 21px;
  font-weight: 700;
  color: #0b152d;
  margin: 0 0 8px;
  line-height: 1.35;
  letter-spacing: -0.015em;
}

.home-mock-card-meta {
  font-size: 13.5px;
  color: #64748b;
  line-height: 1.5;
  margin: 0 0 12px;
  min-height: 0;
}

.home-mock-card-description {
  color: #475569;
  font-size: 14px;
  line-height: 1.65;
  margin: 0 0 20px;
}

.home-mock-card-benefit {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-radius: 10px;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.35;
  min-height: 38px;
  margin-top: auto;
  margin-bottom: 22px;
  width: 100%;
  box-sizing: border-box;
  justify-content: center;
}

.home-mock-card-benefit.is-preparing {
  background: #fff7ed;
  color: #9a3412;
}

.home-mock-card.is-disabled {
  cursor: default;
}

.home-mock-card.is-disabled:hover {
  transform: none;
  border-color: #e2e8f0;
  box-shadow: 0 4px 16px rgba(15, 23, 42, 0.03);
}

.home-mock-benefit-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.home-mock-benefit-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Card CTA Button */
.home-mock-card-cta {
  height: 56px;
  width: 100%;
  border-radius: 16px;
  font-size: 16px;
  font-weight: 700;
  color: #ffffff;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  transition: background-color 0.2s ease, filter 0.2s ease, transform 0.2s ease;
  user-select: none;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  border: 0;
  font-family: inherit;
}

.home-mock-card.is-disabled .home-mock-card-cta,
.home-mock-card.is-disabled:hover .home-mock-card-cta {
  background: #cbd5e1;
  box-shadow: none;
  cursor: not-allowed;
}

.home-mock-cta-arrow {
  display: inline-flex;
  align-items: center;
  transition: transform 0.2s ease;
}

.home-mock-card:hover .home-mock-cta-arrow {
  transform: translateX(4px);
}

.home-mock-card .home-mock-card-icon {
  background: #e0f2fe;
  color: #0284c7;
}
.home-mock-card .home-mock-card-benefit {
  background: #f0f6ff;
  color: #334155;
}
.home-mock-card .home-mock-benefit-icon {
  color: #2563eb;
}
.home-mock-card .home-mock-card-cta {
  background: #1d4ed8;
}
.home-mock-card:hover {
  border-color: #93c5fd;
}
.home-mock-card:hover .home-mock-card-cta {
  background: #1e40af;
}

/* 2. Amber Accent (ก.พ. ภาค ก) */
.home-mock-card-amber .home-mock-card-icon {
  background: #fef3c7;
  color: #d97706;
}
.home-mock-card-amber .home-mock-card-benefit {
  background: #fffbeb;
  color: #334155;
}
.home-mock-card-amber .home-mock-benefit-icon {
  color: #d97706;
}
.home-mock-card-amber .home-mock-card-cta {
  background: #f59e0b;
}
.home-mock-card-amber:hover {
  border-color: #fde68a;
}
.home-mock-card-amber:hover .home-mock-card-cta {
  background: #d97706;
}

/* 3. Green Accent (ครูผู้ช่วย กทม.) */
.home-mock-card-green .home-mock-card-icon {
  background: #dcfce7;
  color: #059669;
}
.home-mock-card-green .home-mock-card-benefit {
  background: #f0fdf4;
  color: #334155;
}
.home-mock-card-green .home-mock-benefit-icon {
  color: #16a34a;
}
.home-mock-card-green .home-mock-card-cta {
  background: #059669;
}
.home-mock-card-green:hover {
  border-color: #86efac;
}
.home-mock-card-green:hover .home-mock-card-cta {
  background: #047857;
}

/* 4. Purple Accent (ครูผู้ช่วยท้องถิ่น) */
.home-mock-card-purple .home-mock-card-icon {
  background: #ede9fe;
  color: #7c3aed;
}
.home-mock-card-purple .home-mock-card-benefit {
  background: #faf5ff;
  color: #334155;
}
.home-mock-card-purple .home-mock-benefit-icon {
  color: #7c3aed;
}
.home-mock-card-purple .home-mock-card-cta {
  background: #5848e0;
}
.home-mock-card-purple:hover {
  border-color: #c4b5fd;
}
.home-mock-card-purple:hover .home-mock-card-cta {
  background: #4736c4;
}

/* Bottom Link */
.home-mock-bottom-wrap {
  margin-top: 34px;
  display: flex;
  align-items: center;
  position: relative;
  z-index: 1;
}

.home-mock-bottom-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: #1d4ed8;
  font-size: 16px;
  font-weight: 700;
  text-decoration: none;
  transition: color 0.2s ease, transform 0.2s ease;
}

.home-mock-bottom-link:hover {
  color: #1e40af;
  text-decoration: none;
}

.home-mock-bottom-icon {
  width: 32px;
  height: 32px;
  border-radius: 9px;
  background: #e0edff;
  border: 1px solid #bfdbfe;
  color: #1d4ed8;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background-color 0.2s ease, border-color 0.2s ease;
}

.home-mock-bottom-link:hover .home-mock-bottom-icon {
  background: #cfe2ff;
  border-color: #93c5fd;
}

.home-mock-bottom-arrow {
  display: inline-flex;
  align-items: center;
  transition: transform 0.2s ease;
}

.home-mock-bottom-link:hover .home-mock-bottom-arrow {
  transform: translateX(4px);
}

/* Dark theme overrides */
:root[data-theme="dark"] .home-mock-container {
  background: linear-gradient(145deg, #0e172e 0%, #111a33 50%, #0d152a 100%);
  border-color: rgba(255, 255, 255, 0.08);
  box-shadow: 0 12px 36px rgba(0, 0, 0, 0.4);
}
:root[data-theme="dark"] .home-mock-rings circle {
  stroke: rgba(120, 151, 255, 0.06);
}
:root[data-theme="dark"] .home-mock-glow {
  background: radial-gradient(circle, rgba(95, 126, 244, 0.15) 0%, rgba(13, 21, 42, 0) 70%);
}
:root[data-theme="dark"] .home-mock-badge {
  background: #1a274e;
  border-color: #2a3c75;
  color: #93c5fd;
}
:root[data-theme="dark"] .home-mock-badge-ic {
  color: #93c5fd;
}
:root[data-theme="dark"] .home-mock-title {
  color: #f1f5f9;
}
:root[data-theme="dark"] .home-mock-title-accent {
  color: #60a5fa;
}
:root[data-theme="dark"] .home-mock-desc {
  color: #94a3b8;
}
:root[data-theme="dark"] .home-mock-card {
  background: #151f3b;
  border-color: rgba(255, 255, 255, 0.08);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
}
:root[data-theme="dark"] .home-mock-card-title {
  color: #f8fafc;
}
:root[data-theme="dark"] .home-mock-card-meta {
  color: #94a3b8;
}
:root[data-theme="dark"] .home-mock-card-description {
  color: #cbd5e1;
}
:root[data-theme="dark"] .home-mock-card-benefit {
  background: rgba(255, 255, 255, 0.05);
  color: #cbd5e1;
}
:root[data-theme="dark"] .home-mock-bottom-link {
  color: #7897ff;
}
:root[data-theme="dark"] .home-mock-bottom-icon {
  background: #1c2850;
  border-color: #2e3e78;
  color: #93c5fd;
}

/* Backwards compatibility aliases */
.supported-field-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
.supported-field-card { min-width: 0; min-height: 134px; padding: 18px; }
.home-section-link { margin-top: 16px; display: inline-flex; align-items: center; gap: 7px; color: var(--primary); font-size: 13.5px; font-weight: 700; }

/* The page's closing offer. A rounded brand panel inside the container rather
   than a full-bleed band: the footer immediately below is already a full-width
   dark surface, and two of those stacked read as one long dark area with a
   seam across it. */
.cta-band {
  position: relative; overflow: hidden; isolation: isolate;
  border-radius: 20px; padding: 32px 40px;
  background: linear-gradient(135deg, #1239c5 0%, #1c47cc 48%, #0b70e8 100%);
  color: #fff; box-shadow: 0 16px 32px rgba(21, 94, 239, .22);
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-lg); align-items: center;
}
/* One light source, top right, so the panel has a direction instead of being a
   flat rectangle of blue. */
.cta-band::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: radial-gradient(560px 320px at 88% -20%, rgba(255, 255, 255, .22), transparent 62%);
}
.cta-band h2 { color: #fff; font-size: clamp(23px, 3.1vw, 30px); margin: 0 0 8px; letter-spacing: -.02em; }
.cta-band p { color: rgba(255, 255, 255, .87); font-size: 14.5px; line-height: 1.65; margin: 0 0 18px; max-width: 58ch; }
.cta-band .eyebrow { background: rgba(255, 255, 255, .14); border-color: rgba(255, 255, 255, .26); color: #fff; }
.cta-band .btn-primary {
  --btn-fg: var(--primary-dark); --btn-border: #fff;
  background: #fff; box-shadow: 0 6px 18px -6px rgba(6, 16, 45, .45);
}
.cta-band .btn-primary:hover { background: #eef2ff; color: var(--primary-dark); filter: none; }
.cta-band .btn-primary::after { display: none; }
.cta-band .btn-outline {
  --btn-bg: rgba(255, 255, 255, .1); --btn-fg: #fff; --btn-border: rgba(255, 255, 255, .38);
}
.cta-band .btn-outline:hover { --btn-bg: rgba(255, 255, 255, .18); color: #fff; }
/* The closing drawing: the same bullseye the page has been arguing for, hit.
   It is a real illustration rather than a ringed icon because at this size an
   icon reads as a placeholder. */
.cta-art-wrap { flex: 0 0 auto; display: flex; justify-content: flex-end; }
.cta-art { width: 220px; height: auto; }

/* VIP offer on the home page. The content stays database-driven; this layer
   gives the existing comparison and price cards the premium hierarchy shown
   in the approved reference. */
.home-vip-section {
  position: relative; overflow: hidden; isolation: isolate;
  background:
    radial-gradient(760px 430px at -8% 8%, rgba(37, 99, 235, .10), transparent 65%),
    radial-gradient(700px 420px at 108% 90%, rgba(59, 130, 246, .10), transparent 66%),
    linear-gradient(180deg, #fbfdff 0%, #f5f9ff 54%, #fbfdff 100%);
}
.home-vip-section::before,
.home-vip-section::after {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  width: 360px; height: 360px; border: 1px solid rgba(37, 99, 235, .10);
  border-radius: 48% 52% 62% 38%; transform: rotate(28deg);
}
.home-vip-section::before { left: -245px; top: -195px; box-shadow: 28px 24px 0 rgba(37, 99, 235, .025); }
.home-vip-section::after { right: -250px; bottom: -220px; box-shadow: -28px -24px 0 rgba(37, 99, 235, .025); }
.vip-heading .eyebrow { padding: 7px 16px; font-size: 13px; letter-spacing: .06em; }
.vip-heading .lead { max-width: 720px; }
.price-card-wrap { min-width: 0; display: flex; flex-direction: column; gap: 10px; }
.price-card-wrap .price-mini { flex: 0 0 auto; }
.price-icon {
  width: 58px; height: 58px; margin: 0 auto 10px; border-radius: 50%;
  display: grid; place-items: center; color: var(--primary);
  background: linear-gradient(145deg, #fff, var(--primary-soft));
  border: 1px solid var(--primary-border); box-shadow: 0 8px 22px rgba(28, 71, 204, .14);
}
.price-mini.is-hero .price-icon {
  color: #fff; background: rgba(255, 255, 255, .08);
  border-color: rgba(255, 255, 255, .55);
  box-shadow: 0 0 0 7px rgba(255, 255, 255, .05), 0 0 26px rgba(96, 165, 250, .45);
}
.vip-assurances {
  max-width: 850px; margin: 24px auto 0; padding: 12px 20px;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  background: rgba(255, 255, 255, .88); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: 0 6px 18px rgba(15, 23, 42, .05);
}
.vip-assurances > div { display: flex; align-items: center; justify-content: center; gap: 10px; min-width: 0; padding: 0 16px; }
.vip-assurances > div + div { border-left: 1px solid var(--border); }
.vip-assurances .ic { flex: 0 0 auto; color: var(--primary); display: inline-flex; }
.vip-assurances b, .vip-assurances small { display: block; }
.vip-assurances b { font-size: 14px; color: var(--primary-dark); line-height: 1.4; }
.vip-assurances small { margin-top: 2px; font-size: 11.5px; color: var(--text-muted); line-height: 1.35; }
.vip-all-packages { margin-top: 18px; text-align: center; }
.vip-all-packages a { display: inline-flex; align-items: center; gap: 8px; font-weight: 700; }
.vip-redeem-slot { max-width: 850px; margin: 18px auto 0; }

/* ------------------------------------------------------- FREE CODE PANEL */
/* One quiet line until it is asked for. Sized and coloured like the panels
   around it so it reads as part of the pricing block, not a promotion. */
.redeem-panel {
  max-width: 850px; margin-inline: auto;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); overflow: hidden;
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.redeem-panel:hover {
  border-color: var(--primary-border);
}
.redeem-toggle {
  width: 100%; display: flex; align-items: center; gap: 12px;
  padding: 16px 20px; min-height: 58px;
  background: none; border: 0; cursor: pointer; text-align: left;
  font: inherit; color: var(--text);
  transition: background var(--t-fast);
}
.redeem-toggle:hover { background: var(--surface-muted); }
.redeem-toggle:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: -3px; }
.redeem-lead { font-size: 15px; font-weight: 700; color: var(--primary-dark); flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px; }
.redeem-hint { font-size: 13px; color: var(--text-muted); flex: 1 1 auto; min-width: 0; }
.redeem-chevron { flex: 0 0 auto; color: var(--text-muted); display: inline-flex; transition: transform var(--t-fast); }
.redeem-toggle[aria-expanded="true"] .redeem-chevron { transform: rotate(180deg); }
.redeem-body { padding: 0 20px 18px; border-top: 1px solid var(--border); }
.redeem-form { display: flex; gap: 10px; align-items: stretch; padding-top: 14px; }
.redeem-form .form-control {
  flex: 1 1 auto; min-width: 0; min-height: 46px;
  font-family: var(--font-num); letter-spacing: .06em; text-transform: uppercase;
}
.redeem-form .btn { flex: 0 0 auto; min-height: 46px; padding-inline: 22px; }
.redeem-note { margin: 10px 0 0; font-size: 13px; color: var(--text-muted); line-height: 1.6; }
.redeem-note:empty { display: none; }
.redeem-note.is-error { color: var(--danger); font-weight: 600; }
.redeem-note.is-success { color: var(--success); font-weight: 600; }
/* The success state replaces the form: there is nothing left to type. */
.redeem-done {
  display: flex; flex-direction: column; gap: 4px;
  margin-top: 14px; padding: 15px 17px;
  background: var(--success-soft);
  border: 1px solid var(--success-border); border-radius: var(--radius);
}
.redeem-done b { font-size: 15px; }
.redeem-done span { font-size: 13.5px; color: var(--text-muted); }
.redeem-done .row { margin-top: 8px; }

/* ------------------------------------------------ HOME RANKING SHOWCASE */
.home-ranking-section { background: #fff; }
.home-ranking-shell {
  position: relative; overflow: hidden; padding: 34px 34px 24px;
  border: 1px solid var(--primary-border); border-radius: 22px;
  background:
    radial-gradient(circle at 87% 22%, rgba(219, 234, 254, .62), transparent 27%),
    radial-gradient(circle at 6% 91%, rgba(224, 231, 255, .54), transparent 24%),
    linear-gradient(145deg, #fbfdff 0%, #f7faff 52%, #fff 100%);
  box-shadow: 0 16px 38px rgba(42, 80, 150, .08);
}
.home-ranking-head {
  position: relative; z-index: 1; display: flex; align-items: center;
  justify-content: space-between; gap: 24px;
}
.home-ranking-head .eyebrow { margin-bottom: 13px; }
.home-ranking-head h2 { margin: 0 0 4px; font-size: clamp(28px, 2.55vw, 40px); line-height: 1.2; }
.home-ranking-head p { margin: 0; color: var(--text-muted); font-size: 15px; }
.home-ranking-head .btn { flex: 0 0 auto; background: rgba(255, 255, 255, .8); }

.ranking-following {
  position: relative; z-index: 1; overflow: hidden; margin-top: 10px;
  border: 1px solid var(--border-strong); border-radius: 16px; background: rgba(255, 255, 255, .9);
  box-shadow: 0 8px 20px rgba(15, 23, 42, .06);
}
.ranking-following-row {
  min-height: 66px; padding: 10px 22px; display: grid;
  grid-template-columns: 48px 42px minmax(150px, 1.3fr) minmax(110px, .72fr) minmax(105px, .55fr) 74px 18px;
  align-items: center; gap: 12px;
}
.ranking-following-row + .ranking-following-row { border-top: 1px solid var(--border); }
.ranking-following-row .rank-no {
  width: 38px; height: 38px; display: grid; place-items: center; border: 1px solid var(--border-strong);
  border-radius: 10px; background: #fff; font-family: var(--font-num); font-weight: 800;
}
.ranking-following-row .avatar {
  width: 36px; height: 36px; margin: 0; display: grid; place-items: center; object-fit: cover;
  border-radius: 50%; color: var(--primary); background: var(--primary-soft);
}
.ranking-following-row .rank-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ranking-following-row .rank-date,
.ranking-following-row .rank-percent { display: inline-flex; align-items: center; gap: 6px; color: var(--text-muted); font-size: 13px; white-space: nowrap; }
.ranking-following-row .rank-points { white-space: nowrap; text-align: right; font-size: 12px; color: var(--text-muted); }
.ranking-following-row .rank-points strong { margin-right: 4px; color: var(--text); font-size: 20px; }
.ranking-following-row .rank-percent { justify-content: flex-end; color: var(--primary); font-weight: 700; }
.ranking-following-row .rank-go { display: inline-flex; color: var(--text-subtle); }
.ranking-reset-note {
  position: relative; z-index: 1; margin: 26px 0 0; display: flex; justify-content: center; align-items: center; gap: 7px;
  color: var(--text-muted); font-size: 12.5px;
}

/* ------------------------------------------------ HOME FINAL VISUAL POLISH
   The reference already shares this page's structure. These desktop-only
   measurements give that structure the wider, more editorial proportions of
   the approved target without changing tablet and phone layouts. */
@media (min-width: 1200px) {
  .container { max-width: 1400px; padding-inline: 32px; }

  .header-inner { gap: 20px; }
  .brand img, .brand-mark { width: 37px; height: 37px; }
  .brand-text b { font-size: 16.5px; }
  .main-nav { gap: 2px; margin-left: 4px; }
  .main-nav a { padding: 9px 11px; font-size: 13.5px; }
  .theme-toggle, .icon-btn { width: 40px; height: 40px; }

  .hero { padding: 42px 0 28px; }
  .hero-card {
    aspect-ratio: 2052 / 766;
    padding: 34px 50px 30px;
  }
  .hero-card-grid { height: 100%; display: flex; align-items: center; }
  .hero-card-content { transform: none; }
  .hero-badge { margin-bottom: 4px; }
  .hero-title { margin-bottom: 14px; font-size: 60px; line-height: 1.1; }
  .hero-description { margin-bottom: 9px; font-size: 18px; line-height: 1.45; }
  .hero-actions { margin-bottom: 24px; }
  .hero-btn-main {
    height: 64px;
    padding-inline: 20px 26px;
    font-size: 22px;
  }
  .hero-btn-play .icon { width: 16px; height: 16px; }
  .hero-btn-sub {
    height: 64px;
    padding-inline: 14px;
    font-size: 21px;
  }
  .hero-btn-sub-ic .icon { width: 20px; height: 20px; }
  .hero-feat-ic .icon { width: 20px; height: 20px; }
  .hero-mascot-wrap {
    width: 150%;
    max-width: 800px;
    animation-name: hero-mascot-float-desktop;
  }

  @keyframes hero-mascot-float-desktop {
    0%   { transform: translate(-8%, 0) scale(1.1); }
    100% { transform: translate(-8%, -8px) scale(1.1); }
  }

  .section-figures { padding-bottom: 24px; }
  .stat-grid { gap: 20px; }
  .stat-card { min-height: 96px; padding: 20px 22px; column-gap: 16px; box-shadow: 0 8px 24px rgba(15, 23, 42, .06); }
  .stat-card .ic { width: 48px; height: 48px; }
  .stat-card b { font-size: 24px; }
  .stat-card > span:last-child { font-size: 13px; }

  .today-grid { grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr); gap: 24px; }
  .daily-card { min-height: 390px; padding: 32px; box-shadow: 0 12px 32px rgba(15, 23, 42, .08); }
  .daily-card .dc-body { padding-right: 260px; }
  .dc-art { width: 300px; right: -4px; filter: drop-shadow(0 20px 28px rgba(4, 28, 92, .3)); }
  .daily-card h3 { font-size: 23px; margin-bottom: 15px; }
  .daily-card .dc-q { min-height: 68px; padding: 13px 16px; font-size: 14px; }
  .daily-card .dc-facts b { font-size: 24px; }
  .daily-card .btn-block { height: 50px; font-size: 15.5px; }
  .plan-today { padding: 28px; }
  .plan-today > h2 { font-size: 22px; }
  .plan-sub { font-size: 13.5px; margin-bottom: 16px; }
  .step-list { gap: 12px; }
  .step { min-height: 72px; padding: 13px 16px; gap: 14px; }
  .step .n { width: 29px; height: 29px; font-size: 14px; }
  .step .ic { width: 38px; height: 38px; }
  .step .body b { font-size: 14.5px; }
  .step .body span { font-size: 12px; }

  .section { padding: 54px 0; }
  .home-vip-section { padding: 68px 0 38px; }
  .home-vip-section .vip-heading { padding-bottom: 28px; }
  .home-vip-section .vip-heading h2 { font-size: 44px; line-height: 1.12; margin: 12px 0 10px; }
  .home-vip-section .vip-heading .lead { font-size: 18px; line-height: 1.6; }
  .home-articles-section { padding-top: 12px; padding-bottom: 24px; background: #fff; }
  .vip-showcase { grid-template-columns: minmax(0, 1.12fr) minmax(0, 1fr); gap: 28px; }
  .plan-compare { border-radius: 20px; box-shadow: 0 12px 34px rgba(15, 23, 42, .08); }
  .plan-compare .card-head { min-height: 72px; padding: 20px 24px; background: #fff; }
  .plan-compare .card-head h3 { font-size: 20px; color: var(--text); }
  .plan-compare table { font-size: 14px; }
  .plan-compare th, .plan-compare td { padding: 13px 18px; }
  .plan-compare .mode .ic { width: 34px; height: 34px; }
  .plan-compare .yes, .plan-compare .no { font-size: 13.5px; }
  .price-pair { grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr); gap: 18px; padding-top: 0; }
  .price-mini { height: auto; min-height: 550px; padding: 28px 20px 22px; border-radius: 20px; box-shadow: 0 10px 28px rgba(15, 23, 42, .07); }
  .price-mini .name { font-size: 20px; color: var(--text); }
  .price-mini .amount { font-size: 60px; margin-top: 8px; }
  .price-mini .amount .unit { font-size: 15px; }
  .price-mini ul { gap: 11px; margin: 16px 0 22px; font-size: 13.5px; }
  .price-mini .btn { min-height: 52px; font-size: 15px; }
  .price-mini.is-hero {
    background:
      radial-gradient(280px 210px at 88% 2%, rgba(78, 160, 255, .40), transparent 66%),
      linear-gradient(160deg, #1764ed 0%, #0c47c9 48%, #082b79 100%);
    border: 2px solid #f4b53f; box-shadow: 0 14px 32px rgba(8, 48, 126, .25), inset 0 0 0 2px rgba(255, 255, 255, .08);
  }
  .price-mini.is-hero .name { color: #fff; }
  .price-mini.is-hero .plan-badge { top: -17px; padding: 7px 15px; font-size: 13px; }

  /* On a wide screen three cards still have room for the big figures — only
     the horizontal padding and the price step down from the pair's scale. */
  .price-pair.is-trio { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 13px; }
  .is-trio .price-mini { height: 100%; min-height: 540px; padding: 26px 14px 22px; }
  .is-trio .price-mini .name { font-size: 17px; }
  .is-trio .price-mini .amount { font-size: 44px; }
  /* The recommended plan's figure leads the row without a second badge or a
     larger card: one step up in size is enough. */
  .is-trio .price-mini.is-hero .amount { font-size: 54px; }
  .is-trio .price-mini .amount .unit { font-size: 13.5px; }
  .is-trio .price-mini ul { gap: 10px; margin: 16px 0 20px; font-size: 12.5px; }
  .is-trio .price-mini .btn { min-height: 48px; font-size: 14px; }
  .is-trio .price-icon { width: 52px; height: 52px; }

  .article-grid { gap: 18px; }
  .article-grid .article-card .body { min-height: 106px; padding: 15px; }
  .article-grid .article-card h3 { font-size: 15px; }
  .article-card { box-shadow: 0 8px 24px rgba(15, 23, 42, .06); }

  .home-cta-section { padding-top: 24px; background: #fff; }
  .cta-band { min-height: 190px; padding: 34px 42px; box-shadow: 0 12px 32px rgba(15, 23, 42, .08); }
  .cta-band h2 { font-size: 30px; }
  .cta-art { width: 286px; filter: drop-shadow(0 18px 24px rgba(3, 21, 70, .32)); }

  .site-footer { padding: 46px 0 24px; margin-top: 54px; }
  .footer-grid { grid-template-columns: 2.05fr repeat(3, minmax(145px, 1fr)); gap: 42px; margin-bottom: 28px; }
  .footer-grid h4 { font-size: 12px; margin-bottom: 15px; }
  .footer-grid ul { gap: 11px; }
  .footer-grid a { font-size: 14px; }
  .footer-social a { width: 39px; height: 39px; }
  .footer-bottom { padding-top: 18px; }
  body:has(main > .hero) .site-footer { margin-top: 20px; }
}

/* ---------------------------------------------------------- 11. EXAM RUNNER */
/* The runner is its own surface: no site header, no footer, no sidebar — the
   only things on screen are the question, the timer, the progress and the
   navigation. Everything else is a distraction from a timed exam. */
.runner { min-height: 100vh; display: flex; flex-direction: column; background: var(--background); }

.runner-bar {
  position: sticky; top: 0; z-index: 60;
  background: var(--surface); border-bottom: 1px solid var(--border);
}
.runner-bar-inner {
  height: 60px; display: flex; align-items: center; gap: var(--space-sm);
}
.runner-title { font-weight: 700; font-size: 15px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.runner-progress-text { font-size: 13px; color: var(--text-muted); font-family: var(--font-num); white-space: nowrap; }

.timer {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 15px; border-radius: var(--radius-pill);
  background: var(--primary-soft); color: var(--primary-dark);
  border: 1px solid var(--primary-border);
  font-family: var(--font-num); font-size: 16px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* Under five minutes the timer turns amber, under one minute red and pulses:
   an escalation the candidate notices without having to watch the clock. */
.timer.warning { background: var(--warning-soft); color: var(--warning); border-color: var(--warning-border); }
.timer.danger  { background: var(--danger-soft);  color: var(--danger);  border-color: var(--danger-border); animation: pulse 1.1s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: .55; } }

.runner-progress { height: 3px; background: var(--surface-muted); }
.runner-progress > span { display: block; height: 100%; background: var(--primary); transition: width var(--t); }

.runner-body { flex: 1 1 auto; padding: var(--space-md) 0 120px; }
/* Capped rather than full-bleed: on a wide monitor a 1fr question column ran
   to well over 100 characters a line, which is tiring to read under time. */
.runner-layout {
  display: grid; grid-template-columns: minmax(0, 1fr) 268px;
  gap: var(--space-md); align-items: start;
  max-width: 1060px; margin: 0 auto;
}

.question-card { padding: var(--space-md); }
.question-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: var(--space); }
.question-no {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 34px; height: 34px; padding: 0 9px; border-radius: var(--radius-sm);
  background: var(--primary); color: var(--primary-contrast);
  font-family: var(--font-num); font-weight: 700; font-size: 15.5px;
}
.question-text { font-size: 19.5px; line-height: 1.75; margin-bottom: var(--space); white-space: pre-line; }
.question-image { border-radius: var(--radius); border: 1px solid var(--border); margin-bottom: var(--space); }

.choices { display: grid; gap: 10px; }
.choice {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 14px 16px; width: 100%; text-align: left;
  background: var(--surface); border: 1.5px solid var(--border);
  border-radius: var(--radius); cursor: pointer;
  font-family: inherit; font-size: 17px; line-height: 1.6; color: var(--text);
  transition: border-color var(--t-fast), background var(--t-fast);
}
.choice:hover { border-color: var(--primary-border); background: var(--primary-soft); }
.choice .key {
  width: 28px; height: 28px; flex: 0 0 auto; border-radius: 8px;
  display: grid; place-items: center; background: var(--surface-muted);
  font-family: var(--font-num); font-weight: 700; font-size: 14.5px; color: var(--text-muted);
  transition: background var(--t-fast), color var(--t-fast);
}
.choice.selected { border-color: var(--primary); background: var(--primary-soft); }
.choice.selected .key { background: var(--primary); color: var(--primary-contrast); }

/* Answered state, used by Daily Question and the review screen. Correctness is
   never signalled by colour alone: the key becomes a tick or a cross too. */
.choice.correct { border-color: var(--success); background: var(--success-soft); }
.choice.correct .key { background: var(--success); color: #fff; }
.choice.wrong { border-color: var(--danger); background: var(--danger-soft); }
.choice.wrong .key { background: var(--danger); color: #fff; }
.choice.is-locked { cursor: default; }
.choice.is-locked:hover { border-color: var(--border); background: var(--surface); }
.choice.is-locked.correct:hover { border-color: var(--success); background: var(--success-soft); }
.choice.is-locked.wrong:hover { border-color: var(--danger); background: var(--danger-soft); }
.choice .share { margin-left: auto; font-size: 12.5px; color: var(--text-muted); font-family: var(--font-num); flex: 0 0 auto; }

/* The bar behind a choice showing what share of people picked it. */
.choice { position: relative; overflow: hidden; }
.choice .fill {
  position: absolute; left: 0; top: 0; bottom: 0; z-index: 0;
  background: color-mix(in srgb, var(--primary) 9%, transparent);
  transition: width var(--t);
}
.choice > * { position: relative; z-index: 1; }

/* Explanation panel */
.explain {
  margin-top: var(--space); padding: var(--space);
  border-radius: var(--radius); border: 1px solid var(--border);
  background: var(--surface-muted);
}
.explain h4 { display: flex; align-items: center; gap: 7px; font-size: 14.5px; margin-bottom: 7px; color: var(--text); }
.explain p { font-size: 14.5px; color: var(--text-muted); line-height: 1.75; margin: 0; }
.explain .trick, .explain.trick {
  margin-top: 12px; padding: 12px 14px; border-radius: var(--radius-sm);
  background: var(--warning-soft); border: 1px solid var(--warning-border);
}
.explain .trick h4, .explain.trick h4 { color: var(--warning); margin-bottom: 5px; font-size: 14.5px; font-weight: 600; }
.explain .trick p, .explain.trick p { color: var(--text); font-size: 14.5px; line-height: 1.7; margin: 0; }

.verdict {
  display: inline-flex; align-items: center; gap: 8px; padding: 9px 16px;
  border-radius: var(--radius-pill); font-weight: 700; font-size: 15px;
}
.verdict.correct { background: var(--success-soft); color: var(--success); }
.verdict.wrong { background: var(--danger-soft); color: var(--danger); }

/* Question navigator */
.navigator { padding: var(--space); position: sticky; top: calc(60px + var(--space)); }
.navigator h4 { font-size: 14px; margin-bottom: 11px; }
.nav-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 7px; }
.nav-btn {
  aspect-ratio: 1; display: grid; place-items: center;
  border: 1.5px solid var(--border-strong); border-radius: var(--radius-xs);
  background: var(--surface); color: var(--text-muted); cursor: pointer;
  font-family: var(--font-num); font-size: 13px; font-weight: 700;
  transition: all var(--t-fast); position: relative;
}
.nav-btn:hover { border-color: var(--primary); }
.nav-btn.answered { background: var(--primary-soft); border-color: var(--primary-border); color: var(--primary-dark); }
.nav-btn.current { background: var(--primary); border-color: var(--primary); color: var(--primary-contrast); }
/* A flagged question carries a corner dot as well as its colour. */
.nav-btn.marked::after {
  content: ''; position: absolute; top: 3px; right: 3px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--warning);
}
.nav-legend { display: grid; gap: 6px; margin-top: 13px; font-size: 12px; color: var(--text-muted); }
.nav-legend span { display: flex; align-items: center; gap: 7px; }
.nav-legend i { width: 13px; height: 13px; border-radius: 4px; border: 1.5px solid var(--border-strong); background: var(--surface); }
.nav-legend i.answered { background: var(--primary-soft); border-color: var(--primary-border); }
.nav-legend i.current { background: var(--primary); border-color: var(--primary); }
.nav-legend i.marked { background: var(--warning); border-color: var(--warning); }

/* Bottom navigation bar of the runner */
.runner-foot {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 70;
  background: var(--surface); border-top: 1px solid var(--border);
  padding: 11px 0 calc(11px + env(safe-area-inset-bottom));
  box-shadow: 0 -3px 14px rgba(22, 37, 88, .07);
}
.runner-foot-inner { display: flex; align-items: center; gap: 10px; }
.runner-foot .spacer { flex: 1 1 auto; }

/* Result page */
.result-hero { text-align: center; padding: var(--space-md) 0; }
.score-ring {
  --pct: 0;
  width: 168px; height: 168px; margin: 0 auto var(--space);
  border-radius: 50%; display: grid; place-items: center; position: relative;
  background: conic-gradient(var(--ring-color, var(--primary)) calc(var(--pct) * 1%), var(--surface-muted) 0);
}
.score-ring::before {
  content: ''; position: absolute; inset: 13px; border-radius: 50%; background: var(--surface);
}
.score-ring .inner { position: relative; text-align: center; }
.score-ring .v { font-family: var(--font-num); font-size: 38px; font-weight: 800; line-height: 1.1; }
.score-ring .v small { font-size: 19px; color: var(--text-muted); font-weight: 700; }
.score-ring .p { font-family: var(--font-num); font-size: 15px; color: var(--text-muted); font-weight: 600; }

.result-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; }
.result-stat {
  text-align: center; padding: 14px 9px; border-radius: var(--radius);
  background: var(--surface-muted); border: 1px solid var(--border);
}

.result-stat .v { font-family: var(--font-num); font-size: 23px; font-weight: 700; line-height: 1.2; }
.result-stat .k { font-size: 12.5px; color: var(--text-muted); margin-top: 2px; }

.cat-perf { display: grid; gap: 13px; }
.cat-perf-row .top { display: flex; justify-content: space-between; gap: 10px; font-size: 14px; margin-bottom: 5px; }
.cat-perf-row .top b { font-family: var(--font-num); }

/* Review list */
.review-item { padding: var(--space); border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface); }
.review-item + .review-item { margin-top: var(--space-sm); }
.review-item.correct { border-left: 3px solid var(--success); }
.review-item.wrong { border-left: 3px solid var(--danger); }
.review-item.skipped { border-left: 3px solid var(--text-subtle); }

/* ------------------------------------------------------------ 12. ADMIN SHELL */
.admin { display: grid; grid-template-columns: 236px 1fr; min-height: 100vh; }

/* The sidebar is dark in both palettes, and so it carries its own colours
   rather than borrowing --surface-inverse — that token flips to near-white in
   the dark palette, which left this navigation as pale text on pale ground. */
.admin-side {
  --side-bg: #101a35;
  --side-fg: #cfd8ee;
  --side-dim: #8092b8;
  --side-hover: rgba(255, 255, 255, .07);
  background: var(--side-bg); color: var(--side-fg);
  display: flex; flex-direction: column; position: sticky; top: 0; height: 100vh; overflow-y: auto;
}
:root[data-theme="dark"] .admin-side { --side-bg: #0d1428; }
.admin-side .brand {
  padding: var(--space); color: #fff;
  border-bottom: 1px solid rgba(255, 255, 255, .08); margin-bottom: 6px;
}
.admin-side .brand:hover { color: #fff; }
.admin-side .brand-text span { color: var(--side-dim); }
.admin-nav { padding: 6px 10px var(--space-md); display: grid; gap: 2px; }
.admin-nav .group {
  font-size: 10.5px; font-weight: 700; color: var(--side-dim);
  padding: var(--space-sm) 11px 5px; letter-spacing: .06em; text-transform: uppercase;
}
.admin-nav a {
  display: flex; align-items: center; gap: 10px; padding: 9px 11px;
  border-radius: var(--radius-sm); color: var(--side-fg); font-size: 14.5px; font-weight: 500;
  transition: background var(--t-fast), color var(--t-fast);
}
.admin-nav a .icon { color: var(--side-dim); transition: color var(--t-fast); }
.admin-nav a:hover { background: var(--side-hover); color: #fff; text-decoration: none; }
.admin-nav a:hover .icon { color: #fff; }
.admin-nav a.active { background: var(--primary); color: #fff; font-weight: 600; }
.admin-nav a.active .icon { color: #fff; }
/* The first group has no label — it is the dashboard on its own — so it takes
   the padding the missing heading would have provided. */
.admin-nav > a:first-child { margin-top: var(--space-sm); }

/* The tab strip for a screen made of several panels or pages. Consolidating
   the sidebar moved a number of tools inside the screen they belong to; this
   is the control that reaches them, and it sits directly under the page head
   so it reads as part of the title block rather than as page content. */
.admin-tabs {
  display: flex; gap: 2px; flex-wrap: wrap;
  border-bottom: 1px solid var(--border);
  margin: calc(var(--space-md) * -1 + 2px) 0 var(--space-md);
  padding-bottom: 0;
}
.admin-tab {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 14px; margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  font-size: 14px; font-weight: 600; color: var(--text-muted);
  transition: color var(--t-fast), border-color var(--t-fast);
}
.admin-tab:hover { color: var(--text); text-decoration: none; }
.admin-tab.is-active { color: var(--primary); border-bottom-color: var(--primary); }
.admin-tab-count {
  min-width: 19px; padding: 0 6px; border-radius: var(--radius-pill);
  background: var(--danger); color: #fff;
  font: 700 10px/17px var(--font-num); text-align: center;
}

/* The statistics row sizes itself to however many tiles it is given: four on
   most screens, six on the dashboard, without a caller picking a grid class
   that then breaks when a tile is added. */
.admin-stats {
  display: grid; gap: var(--space-sm); margin-bottom: var(--space-md);
  grid-template-columns: repeat(auto-fit, minmax(178px, 1fr));
}
.stat-link { color: inherit; display: block; transition: border-color var(--t-fast), transform var(--t-fast); }
.stat-link:hover { border-color: var(--primary); text-decoration: none; transform: translateY(-1px); }

/* The admin two-column layout: a main column and a narrower companion.
 *
 * This exists because the ratio used to be written inline on each screen
 * (style="grid-template-columns:minmax(0,1.6fr) minmax(0,1fr)"), and an inline
 * declaration cannot be overridden by a media query — so every one of those
 * screens stayed two columns on a phone, at roughly 180px and 130px wide. The
 * ratio now travels as two custom properties, which a media query is free to
 * ignore when it collapses the grid.
 *
 *   <div class="admin-split" style="--split-a:1.6fr">
 */
.admin-split {
  display: grid; align-items: start; gap: var(--space-md);
  grid-template-columns: minmax(0, var(--split-a, 1.4fr)) minmax(0, var(--split-b, 1fr));
}
@media (max-width: 1024px) {
  .admin-split { grid-template-columns: minmax(0, 1fr); }
}

/* The settings screen. One readable column rather than two: the panels are
   short now that they are split across tabs, and a form field 900px wide is
   harder to fill in than one at a comfortable measure. */
.settings-grid { display: grid; gap: var(--space); max-width: 780px; }

/* Quick actions: the four things an administrator opens the panel to do.
   Four across, then two — never three-plus-one, which reads as a row that
   failed to finish rather than as a deliberate layout. */
.admin-quick { display: grid; gap: var(--space-sm); grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1024px) { .admin-quick { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.admin-quick a {
  display: flex; align-items: center; gap: 11px;
  padding: 13px var(--space); border: 1px solid var(--border);
  border-radius: var(--radius); background: var(--surface);
  color: var(--text); font-size: 14.5px; font-weight: 600;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.admin-quick a:hover { border-color: var(--primary); background: var(--primary-soft); text-decoration: none; }
.admin-quick a .icon { color: var(--primary); flex: 0 0 auto; }

/* "Needs attention": a list of things to do, each a link to where it is done.
   A row is only ever here because there is something to act on, so the list
   disappears entirely when the site is in good order. */
.admin-todo { display: grid; }
.admin-todo a {
  display: flex; align-items: center; gap: 11px;
  padding: 11px var(--space); border-bottom: 1px solid var(--border);
  color: var(--text); font-size: 14px;
}
.admin-todo a:last-child { border-bottom: 0; }
.admin-todo a:hover { background: var(--surface-hover); text-decoration: none; }
.admin-todo .todo-label { flex: 1 1 auto; min-width: 0; }
.admin-todo .todo-count { font-family: var(--font-num); font-weight: 700; font-size: 13px; }
.admin-todo .icon:first-child { flex: 0 0 auto; }

/* The recent-activity feed. Deliberately plain: a time, an actor and what they
   did, with no card of its own per row. */
.admin-feed { display: grid; }
.admin-feed li {
  display: flex; gap: 10px; align-items: baseline;
  padding: 9px var(--space); border-bottom: 1px solid var(--border);
  font-size: 13.5px; list-style: none;
}
.admin-feed li:last-child { border-bottom: 0; }
.admin-feed .when { flex: 0 0 auto; color: var(--text-subtle); font-size: 12px; font-family: var(--font-num); }
.admin-feed .who { font-weight: 600; }
.admin-feed .what { color: var(--text-muted); min-width: 0; }

/* A row of controls that acts on the table below it. It appears only once
   something is ticked, so the table is not permanently topped by a toolbar of
   disabled buttons. */
.bulk-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px var(--space); margin-bottom: var(--space-sm);
  background: var(--primary-soft); border: 1px solid var(--primary);
  border-radius: var(--radius); font-size: 14px;
}
.bulk-bar b { font-family: var(--font-num); }
.bulk-bar .spacer { flex: 1 1 auto; }
/* display:flex outranks the browser's own [hidden] rule, so say it again —
   otherwise the bar is on screen before anything has been ticked. */
.bulk-bar[hidden] { display: none; }

/* A table whose rows can be ticked. The checkbox column never grows. */
/* ------------------------------------------------- Admin: the exam catalogue */
/* A list of several hundred sets, read by scanning. Everything here works
   towards that: one strong line per row, the rest quiet, and a row height that
   fits more of the list on screen without the text closing up. */
.exam-admin-summary {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  margin: 0 0 var(--space-sm);
  color: var(--text-muted); font-size: 13.5px;
}
.exam-admin-summary b { color: var(--text); }
.exam-admin-summary .sep { color: var(--border-strong); }
.exam-admin-per { margin: 0; font-size: 13px; color: var(--text-muted); }
.exam-admin-per-select { width: auto; min-width: 104px; }

/* The ⋯ menu hangs out of the cell, so this wrapper must not clip it. Below
   1024px .table-stack turns the row into a block and there is nothing to
   scroll sideways, so nothing is lost by dropping the overflow entirely. */
.exam-admin-table { overflow: visible; }

.table .exam-admin-name { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.exam-admin-title {
  font-size: 14.5px; font-weight: 600; line-height: 1.4; color: var(--text);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
a.exam-admin-title:hover { color: var(--primary); text-decoration: none; }
.exam-admin-sub {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  color: var(--text-subtle); font-size: 11.5px;
}
/* Flags sit after the slug rather than beside the name: a badge next to a
   two-line title is the thing that makes the name hard to read. */
.badge.exam-admin-flag { font-size: 10.5px; padding: 1px 6px; }

.exam-admin-taxonomy { display: flex; flex-direction: column; gap: 1px; min-width: 0; font-size: 12.5px; }
.exam-admin-taxonomy .lineage { color: var(--text-subtle); font-size: 11.5px; }
.exam-admin-taxonomy .subject { color: var(--text); font-weight: 600; }
.exam-admin-taxonomy .topic {
  color: var(--text-muted);
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;
}

.table .exam-admin-when { white-space: nowrap; }
.exam-admin-when .d { display: block; font-size: 13px; color: var(--text); }
.exam-admin-when .t { display: block; font-size: 11.5px; color: var(--text-subtle); }

.exam-admin-actions { display: flex; align-items: center; gap: 5px; justify-content: flex-end; }
.exam-admin-more { position: relative; }
.exam-admin-more .dropdown { min-width: 196px; }
.exam-admin-more .dropdown button, .exam-admin-more .dropdown a { font-size: 13.5px; padding: 8px 10px; }
.exam-admin-more .dropdown .is-danger { color: var(--danger); }
.exam-admin-more .dropdown .is-danger:hover { background: var(--danger-soft, var(--surface-hover)); }

.exam-admin-page-note { margin: var(--space-sm) 0 0; color: var(--text-muted); font-size: 13px; }
.exam-admin-page-note b { color: var(--text); }

/* The selection's own actions, above the categorise controls they share the
   toolbar with. A rule between the two says they are separate decisions: one
   changes what the sets are, the other only where they file. */
.exam-bulk-ops {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  width: 100%; margin-bottom: 12px;
}
.exam-bulk-ops-note {
  display: inline-flex; align-items: center; gap: 5px;
  color: var(--text-subtle); font-size: 12px;
}
.exam-bulk-divider {
  width: 100%; height: 1px; margin: 0 0 12px;
  background: var(--border);
}

/* Denser rows, but only on this table: 14px top and bottom reads as compact
   without the two lines in the first column touching. */
.exam-admin-table .table th, .exam-admin-table .table td { padding: 14px 13px; }
.exam-admin-table .table td { vertical-align: top; }

@media (max-width: 1024px) {
  /* Stacked rows: the menu is inside a block, so it opens against the row. */
  .exam-admin-actions { justify-content: flex-start; }
  .exam-admin-more .dropdown { right: auto; left: 0; }
}

.table td.pick, .table th.pick { width: 34px; padding-right: 0; }
.table td.pick input, .table th.pick input { width: 17px; height: 17px; accent-color: var(--primary); }

.admin-main { min-width: 0; display: flex; flex-direction: column; }
.admin-top {
  height: 62px; background: var(--surface); border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: var(--space-sm); padding: 0 var(--space-md);
  position: sticky; top: 0; z-index: 50;
}
/* Admin screens are dense; a full-bleed 2560px table is unreadable, so the
   content keeps a working maximum and centres beyond it. */
.admin-content { padding: var(--space-md); flex: 1 1 auto; width: 100%; max-width: 1560px; }
.admin-page-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--space); flex-wrap: wrap;
  margin-bottom: var(--space-md); padding-bottom: var(--space);
  border-bottom: 1px solid var(--border);
}
.admin-page-head h1 { font-size: 23px; margin: 0; letter-spacing: -.015em; }
.admin-page-head .lead { color: var(--text-muted); font-size: 14px; margin: 4px 0 0; }

.filter-bar {
  display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end;
  padding: var(--space); background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); margin-bottom: var(--space);
}
.filter-bar .form-group { margin: 0; min-width: 160px; flex: 1 1 160px; }
.filter-bar .form-group.grow { flex: 2 1 240px; }

/* A picker list used by the exam builder and the daily-question editor. */
.picker { border: 1px solid var(--border); border-radius: var(--radius); max-height: 420px; overflow-y: auto; }
.picker-item { display: flex; gap: 11px; padding: 11px 13px; border-bottom: 1px solid var(--border); align-items: flex-start; }
.picker-item:last-child { border-bottom: 0; }
.picker-item:hover { background: var(--surface-hover); }
.picker-item .q { font-size: 14px; line-height: 1.55; }
.picker-item .meta { font-size: 12px; color: var(--text-muted); margin-top: 3px; display: flex; gap: 8px; flex-wrap: wrap; }

/* Sortable chosen-question list */
.chosen-list { display: grid; gap: 7px; }
.chosen-item {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface);
}
.chosen-item .n {
  width: 26px; height: 26px; flex: 0 0 auto; border-radius: 7px; display: grid; place-items: center;
  background: var(--primary-soft); color: var(--primary-dark); font-family: var(--font-num); font-weight: 700; font-size: 12.5px;
}
.chosen-item .q { flex: 1 1 auto; min-width: 0; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Simple bar chart, drawn with CSS — no charting library for six bars. */
.bars { display: flex; align-items: flex-end; gap: 6px; height: 150px; padding-top: var(--space); }
.bars .bar { flex: 1 1 0; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 5px; min-width: 0; }
.bars .bar i {
  display: block; width: 100%; border-radius: 5px 5px 0 0;
  background: var(--primary); min-height: 3px; transition: height var(--t);
}
.bars .bar span { font-size: 10.5px; color: var(--text-muted); white-space: nowrap; font-family: var(--font-num); }

/* ------------------------------------------------------- Article editor */
/* The writing surface on /admin/article_edit.php. It borrows .article-body so
   a heading, a quote or a list is the size and weight it will be on the public
   page — the author is looking at the article, not at a form field. */

.editor-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: var(--space-sm); }
.editor-tab {
  appearance: none; background: none; border: 0; border-bottom: 2px solid transparent;
  padding: 9px 14px; margin-bottom: -1px; cursor: pointer;
  font: inherit; font-size: 14px; font-weight: 600; color: var(--text-muted);
  transition: color var(--t-fast), border-color var(--t-fast);
}
.editor-tab:hover { color: var(--text); }
.editor-tab.is-active { color: var(--primary); border-bottom-color: var(--primary); }

.editor-toolbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 3px;
  padding: 7px 9px; background: var(--surface-muted);
  border: 1px solid var(--border); border-radius: var(--radius) var(--radius) 0 0;
  border-bottom: 0;
}
.editor-toolbar button {
  appearance: none; background: none; border: 1px solid transparent; border-radius: var(--radius-sm);
  min-width: 30px; height: 30px; padding: 0 8px; cursor: pointer;
  font: inherit; font-size: 13.5px; line-height: 1; color: var(--text);
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}
.editor-toolbar button:hover { background: var(--surface); border-color: var(--border); }
.editor-toolbar button.is-active { background: var(--primary-soft); border-color: var(--primary-soft); color: var(--primary-dark); }
.editor-toolbar button:disabled { opacity: .5; cursor: default; }
.editor-toolbar select {
  height: 30px; padding: 0 8px; font: inherit; font-size: 13.5px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text);
}
.editor-sep { width: 1px; height: 20px; background: var(--border); margin: 0 4px; }

/* The colour pickers: a letter A over the colour it will apply, with the
   native swatch itself stretched behind and hidden. */
.editor-color {
  position: relative; overflow: hidden; width: 30px; height: 30px;
  border-radius: var(--radius-sm); cursor: pointer;
  display: grid; place-items: center; border: 1px solid transparent;
}
.editor-color:hover { background: var(--surface); border-color: var(--border); }
.editor-color > span { font-size: 14px; font-weight: 700; pointer-events: none; }
.editor-color-highlight > span { background: #fff3b0; color: #1c2440; padding: 0 3px; border-radius: 3px; }
.editor-color input[type="color"] {
  position: absolute; inset: auto 0 -2px 0; height: 6px; width: 100%;
  border: 0; padding: 0; background: none; cursor: pointer;
}

.editor-canvas { position: relative; }
.editor-surface {
  min-height: 340px; max-height: 70vh; overflow-y: auto;
  padding: var(--space) var(--space-md);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 0 0 var(--radius) var(--radius);
  font-size: 16px;
}
.editor-surface:focus { outline: 2px solid var(--primary); outline-offset: -2px; }
.editor-surface img { max-width: 100%; height: auto; cursor: pointer; }
/* contenteditable keeps an empty <p><br></p> inside it, so :empty never
   matches — the script sets this class instead. */
.editor-surface.is-empty::before {
  content: attr(data-placeholder); color: var(--text-subtle); pointer-events: none;
  display: block; font-size: 16px;
}

/* Selection frame and size bar. Both are siblings of the editable surface, so
   nothing here can ever be captured into the saved HTML. */
.editor-image-frame { position: absolute; border: 2px solid var(--primary); pointer-events: none; }
.editor-handle {
  position: absolute; width: 11px; height: 11px; background: var(--surface);
  border: 2px solid var(--primary); border-radius: 50%; pointer-events: auto;
}
.editor-handle[data-handle="tl"] { top: -6px; left: -6px; cursor: nwse-resize; }
.editor-handle[data-handle="tr"] { top: -6px; right: -6px; cursor: nesw-resize; }
.editor-handle[data-handle="bl"] { bottom: -6px; left: -6px; cursor: nesw-resize; }
.editor-handle[data-handle="br"] { bottom: -6px; right: -6px; cursor: nwse-resize; }
.editor-image-bar {
  position: absolute; z-index: 5; display: flex; align-items: center; gap: 3px;
  padding: 4px 6px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
}
.editor-image-bar button {
  appearance: none; background: none; border: 0; border-radius: var(--radius-sm);
  padding: 4px 8px; cursor: pointer; font: inherit; font-size: 12.5px; color: var(--text);
}
.editor-image-bar button:hover { background: var(--surface-hover); }
.editor-image-bar button.is-active { background: var(--primary-soft); color: var(--primary-dark); font-weight: 600; }

/* Cover thumbnail beside the file input. */
.cover-preview img {
  width: 100%; border-radius: var(--radius); border: 1px solid var(--border); display: block;
}

/* A sketch of the search result, so the SEO fields are edited against
   something recognisable rather than in the abstract. */
.serp-preview {
  padding: var(--space); background: var(--surface-muted);
  border: 1px solid var(--border); border-radius: var(--radius);
}
.serp-title {
  color: var(--primary); font-size: 16px; line-height: 1.35; font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.serp-url { color: var(--success); font-size: 12.5px; margin: 3px 0 5px; word-break: break-all; }
.serp-desc {
  color: var(--text-muted); font-size: 13px; line-height: 1.6;
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
}

/* .modal-backdrop is display:grid, which outranks the browser's own
   [hidden] rule — say it again so the link dialog can be toggled with the
   attribute like everything else on the page. */
.modal-backdrop[hidden] { display: none; }

@media (max-width: 900px) {
  .editor-surface { min-height: 260px; }
}

/* ============================================================== 13. MOTION */
/* One motion system for the whole site, so nothing has to hand-roll its own.
   Everything here is additive: the hidden states below apply only once the
   script has marked the document with .js-reveal, so with JavaScript off (or
   broken) every element is simply visible and nothing is lost.

   The reduced-motion block near the top of this file already collapses every
   duration to nothing, so a reader who has asked for stillness gets the final
   state instantly rather than a stripped-down animation. */

/* --------------------------------------------------------- Scroll reveal */
.js-reveal [data-reveal] {
  opacity: 0;
  transition:
    opacity var(--t-reveal) var(--reveal-delay, 0ms),
    transform var(--t-reveal) var(--reveal-delay, 0ms),
    filter var(--t-reveal) var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}
/* Only the three the rule list actually assigns. */
.js-reveal [data-reveal="up"]    { transform: translateY(26px); }
.js-reveal [data-reveal="left"]  { transform: translateX(-30px); }
.js-reveal [data-reveal="scale"] { transform: scale(.94); }
.js-reveal [data-reveal].is-in {
  opacity: 1; transform: none; filter: none;
  /* Released once the element has arrived, so it stops costing a layer. */
  will-change: auto;
}

/* ------------------------------------------------------- Hero entrance */
/* The hero animates on load rather than on scroll — it is already in view.
   Each element follows the one above it, so the eye is led down the column in
   the order the copy is meant to be read. */
/* Driven by a transition, not a keyframe animation, and the difference is not
   cosmetic. An animation advances on the document's animation clock, which a
   browser freezes whenever the page is not visible — a background tab, and the
   off-screen render a full-page screenshot tool performs. A frozen clock holds
   the animation at 0%, so anything whose only route back to opacity 1 was that
   animation stays invisible and photographs as a blank rectangle. A transition
   has no such dependency: its target value IS the computed style, so when the
   clock never ticks the element simply appears, finished, on the first paint. */
.js-reveal .hero-grid > div > *,
.js-reveal .hero-visual {
  opacity: 0; transform: translateY(24px);
  transition: opacity 900ms var(--spring), transform 900ms var(--spring);
}
.js-reveal .hero-grid > div > :nth-child(1) { transition-delay: 80ms; }
.js-reveal .hero-grid > div > :nth-child(2) { transition-delay: 170ms; }
.js-reveal .hero-grid > div > :nth-child(3) { transition-delay: 260ms; }
.js-reveal .hero-grid > div > :nth-child(4) { transition-delay: 350ms; }
.js-reveal .hero-grid > div > :nth-child(5) { transition-delay: 440ms; }
.js-reveal .hero-grid > div > :nth-child(6) { transition-delay: 530ms; }
.js-reveal .hero-visual { transition-delay: 240ms; }
/* Script adds .hero-in on the frame after load, and again on a timer in case
   that frame never comes. */
.js-reveal.hero-in .hero-grid > div > *,
.js-reveal.hero-in .hero-visual { opacity: 1; transform: none; }

/* Kept for the mobile navigation, which is the one place a keyframe is safe:
   it only ever plays in response to a tap, so the page is visible by
   definition and the animation clock is certainly running. */
@keyframes rise { to { opacity: 1; transform: none; } }

/* The float can only start once the entrance has finished, or the two
   transforms fight and the panel jumps. */
.hero-visual { animation-play-state: paused; }
.js-reveal .hero-visual.is-settled {
  animation: hero-float 7s ease-in-out infinite alternate;
  animation-play-state: running;
  opacity: 1;
}
html:not(.js-reveal) .hero-visual { animation-play-state: running; }

/* ------------------------------------------------------------ Stagger */
/* A grid whose children arrive one after another. The index is set by script
   as an inline --reveal-delay, so any number of children works. */
/* Transition, not animation — see the note on the hero entrance above. These
   are the cards, so this is the rule that decides whether a screenshot of the
   page contains its content. */
.js-reveal [data-reveal-group] > * {
  opacity: 0;
  transition: opacity var(--t-reveal) var(--reveal-delay, 0ms);
}
.js-reveal [data-reveal-group].is-in > * { opacity: 1; }

/* ------------------------------------------------------- Sticky header */
/* The header is flat until the page scrolls under it, then it lifts. Without
   this the header and the page read as one flat plane. */
.site-header {
  transition: box-shadow var(--t), background var(--t), border-color var(--t);
}
.site-header.is-stuck {
  box-shadow: 0 4px 16px rgba(15, 23, 42, .04);
}

/* ---------------------------------------------------------------- Ripple */
/* Where the pointer landed, expanding outward. Script inserts the span and
   removes it when the animation ends. */
.ripple {
  position: absolute; border-radius: 50%; pointer-events: none;
  transform: translate(-50%, -50%) scale(0);
  background: radial-gradient(circle, rgba(255, 255, 255, .55), rgba(255, 255, 255, 0) 70%);
  animation: ripple 620ms var(--ease) forwards;
}
.btn-outline .ripple, .btn-ghost .ripple, .btn-secondary .ripple {
  background: radial-gradient(circle, color-mix(in srgb, var(--primary) 30%, transparent), transparent 70%);
}
@keyframes ripple {
  to { transform: translate(-50%, -50%) scale(1); opacity: 0; }
}
.btn, .pill, .choice, .nav-btn { position: relative; overflow: hidden; }

/* ------------------------------------------------------- Counting figures */
/* A number mid-count must not change width on every frame, or the row jitters.
   Tabular figures are already set on .num; this reserves the final width. */
.is-counting { font-variant-numeric: tabular-nums; }

/* ----------------------------------------------------------- Bars & rings */
/* A progress bar fills from zero when it first comes into view rather than
   appearing already full, which is what makes the number feel earned. */
.progress > span { transition: width 1100ms var(--spring); }
/* A slow highlight travelling along a filled bar. */
.progress > span::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .45), transparent);
  transform: translateX(-100%);
  animation: bar-sheen 2.6s var(--ease) 1.1s infinite;
}
.progress { position: relative; }
.progress > span { position: relative; overflow: hidden; }
@keyframes bar-sheen { to { transform: translateX(200%); } }

.score-ring { transition: --pct 1400ms var(--spring); }
@property --pct { syntax: '<number>'; inherits: false; initial-value: 0; }

/* -------------------------------------------------------------- Accents */
/* Small, repeated feedback: an icon inside a hovered control leans toward the
   direction it will take you. */
.btn:hover .icon { transition: transform var(--t); }
.btn-primary:hover .icon, .btn-vip:hover .icon { transform: translateX(2px); }
.pill { transition: transform var(--t-fast), background var(--t-fast), border-color var(--t-fast), color var(--t-fast); }
.pill:hover { transform: translateY(-2px); }
.badge { transition: transform var(--t-fast); }
a.badge:hover { transform: translateY(-1px); }

/* The category tile's icon comes forward with the tile. */
.cat-icon { transition: transform var(--t-slow), background var(--t), color var(--t); }
.card-link:hover .cat-icon { transform: scale(1.08) rotate(-4deg); }

/* An answer choice presses in when picked. */
.choice { transition: border-color var(--t-fast), background var(--t-fast), transform var(--t-fast); }
.choice:not(.is-locked):active { transform: scale(.99); }
.choice.selected .key, .choice.correct .key, .choice.wrong .key { animation: pop 320ms var(--spring); }
@keyframes pop { 0% { transform: scale(.6); } 60% { transform: scale(1.12); } to { transform: scale(1); } }

/* The VIP mark has a slow shine, since it is the one thing on the page that is
   meant to look expensive. */
.vip-mark { position: relative; overflow: hidden; }
.vip-mark::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(105deg, transparent 40%, rgba(255, 255, 255, .55) 50%, transparent 60%);
  transform: translateX(-140%);
  animation: vip-shine 4.5s var(--ease) 1.2s infinite;
}
@keyframes vip-shine { 0%, 55% { transform: translateX(-140%); } 100% { transform: translateX(140%); } }

/* The featured plan breathes very slightly, marking it without a badge. */
.plan-featured { animation: featured 5s ease-in-out infinite alternate; }
@keyframes featured {
  from { box-shadow: 0 12px 30px -12px rgba(217, 119, 6, .28); }
  to   { box-shadow: 0 18px 42px -12px rgba(217, 119, 6, .45); }
}

/* ------------------------------------------------------------- RESPONSIVE */

/* Tablet — the runner navigator moves into a collapsible panel. */
/* Tablet. The hero keeps both columns for as long as the copy stays readable;
   the drawing is what gives way, since it is the only decorative thing in the
   row. */
/* ===========================================================================
   HOME HERO — one composition for every viewport at or below 1199px
   ---------------------------------------------------------------------------
   The 768px tablet is the master. A phone is the same hero scaled down, not a
   hero of its own: the copy stays in its left column, the artwork stays in the
   right band, the CTA row and the feature row keep their arrangement, and the
   background keeps one anchor throughout.

   Every value below is a clamp whose vw term resolves to the tablet's number
   at exactly 768px, so 768 renders as it did before and 430 -> 360 slide down
   the same curve. That is why there are no per-phone composition overrides
   further down the file any more.
   =========================================================================== */
@media (max-width: 1199px) {
  .hero { padding: 28px 0 20px; }
  .hero-card {
    padding: 34px 28px 30px;
    border-radius: 24px;
    /* One anchor for every size at or below 1199px. `cover` crops the sides of
       a narrow card, and left-of-centre is what keeps the mascot in the right
       band instead of dragging it under the copy. Phones deliberately do not
       redefine this. */
    background-position: 48% center;
  }
  /* The text/artwork split is frozen from here down. This single number is the
     whole reason a phone still reads as the 768px hero. */
  .hero-card-content { width: 58%; min-width: 0; }
  .hero-title { font-size: clamp(30px, 3.4vw, 38px); }
  .hero-actions {
    display: flex; flex-direction: row; align-items: center; flex-wrap: wrap;
    gap: 10px; margin-bottom: 22px;
  }
  .hero-btn-main { height: 50px; padding: 0 16px 0 11px; font-size: 14.5px; }
  .hero-btn-play { width: 28px; height: 28px; }
  .hero-actions-secondary { display: flex; align-items: center; gap: 10px; }
  .hero-btn-sub { height: 48px; padding: 0 12px; font-size: 13px; }
  .hero-btn-sub-ic { display: inline-flex; align-items: center; justify-content: center; }
  /* Four nowrap items do not fit 58% of a tablet either, so wrapping is part
     of the master composition — not something phones invented. Dividers and
     icons stay. */
  .hero-features { flex-wrap: wrap; row-gap: 8px; }
  .hero-feat-item { padding: 0 10px; font-size: 12px; }
  .hero-feat-ic .icon { width: 16px; height: 16px; }
}

/* ---------------------------------------------------------------------------
   PHONES (<=768): the 768px hero, scaled — not re-laid out.
   ---------------------------------------------------------------------------
   Master measured at viewport 768: card 689 x 396.97 (ratio 1.7357),
   copy column 53.12%, artwork band 42.68%, title 30px, description 14.5px,
   primary 50px tall, secondary 48px, features 12px on two lines.

   Two mechanics carry that whole composition down to 360px:

   1. `aspect-ratio` is locked to the master's own 1.7357. Because the ratio no
      longer changes with the viewport, `background-size: cover` resolves to the
      SAME crop at every width — the mascot keeps its size relative to the card
      and its place in the frame, instead of being re-zoomed by a taller box.
      A locked ratio is also why the hero gets shorter as the screen narrows
      rather than growing to swallow its own content.

   2. One scale factor for everything. `.hero > .container` becomes a query
      container, so 1cqw is exactly 1% of the real card width, and every value
      below is that property's master pixel size expressed against the 689px
      master card (px / 689 * 100). Nothing is clamped and nothing is tuned per
      breakpoint, so type, padding, gaps, icons and buttons all shrink by the
      same factor and the composition is preserved by construction.
   --------------------------------------------------------------------------- */
@media (max-width: 768px) {
  .hero { padding: 3.646vw 0 2.604vw; }

  /* The query container. Scoped to the hero so no other .container changes. */
  .hero > .container { container-type: inline-size; }

  .hero-card {
    /* The master ratio as a FLOOR, not a cap. A locked `aspect-ratio` gives the
       card a height that ignores its own content, so anything the copy column
       needs beyond that height (Thai line metrics differ per engine — iOS
       Safari runs taller than Chrome) spills out through the bottom edge, which
       is what cut the features row in half on iPhone. `min-height` is the same
       689:396.97 box (396.97 / 689 = 57.615% of the card's width) at every
       width — so `background-size: cover` still resolves to the identical crop
       — but the card may grow the few pixels a taller engine asks for. */
    min-height: 57.615cqw;
    padding: 4.9346cqw 4.0639cqw 4.3542cqw;
    border-radius: 3.4833cqw;
    /* Inherited from the master and deliberately not restated per breakpoint:
       background-size: cover; background-position: 48% center. */
  }
  /* The card is border-box, so the grid fills what is left inside its own
     4.9346/4.3542cqw padding: 57.615 - 9.2888 = 48.3262cqw. */
  .hero-card-grid { min-height: 48.3262cqw; display: flex; align-items: center; }
  /* `min-width: 0` is what actually holds the 53.12%. As a flex item the copy
     column cannot shrink below its own min-content, and the features grid's
     min-content is two nowrap columns — wider than 53.12% on a phone. So the
     column grew past its share and pushed the composition out through the
     card's right padding (the features row bleeding off-screen on iPhone). */
  .hero-card-content { width: 53.12%; min-width: 0; }

  /* Thai has no inter-word spaces, so the browser breaks wherever it can and
     left ragged lines and an orphan ("...วิเคราะห์จุด / อ่อน"). `balance` evens the
     headline's two lines; `pretty` stops the description ending on a stray
     fragment. Both are progressive — older engines simply ignore them. */
  .hero-title { font-size: 4.3542cqw; line-height: 1.22; margin-bottom: 1.4514cqw; text-wrap: balance; }
  /* `balance` rather than `pretty`: with the authored break gone, pretty left
     the line splitting mid-word ("...วิเคราะห์จุด / อ่อน"), while balance evens the
     two lines and breaks at a real word boundary — which keeps "จุดอ่อน" whole
     and on the same line as "เพื่อเตรียมสอบได้อย่างมั่นใจ". */
  .hero-description { font-size: 2.1045cqw; line-height: 1.65; margin-bottom: 2.6125cqw; text-wrap: balance; }
  /* The authored break splits the sentence after "...จุดอ่อน", which on a
     narrower column left "เพื่อเตรียมสอบได้อย่างมั่นใจ" stranded on a third line of
     its own. Dropping the break lets the copy flow, so it closes up onto the
     same line as "จุดอ่อน". The desktop (>768) keeps its authored break. */
  .hero-desc-br { display: none; }

  .hero-actions { gap: 1.4514cqw; margin-bottom: 3.1930cqw; }
  .hero-btn-main {
    height: 7.2569cqw;
    padding: 0 2.3222cqw 0 1.5965cqw;
    font-size: 2.1045cqw;
    border-radius: 1.7417cqw;
  }
  .hero-btn-play { width: 4.0639cqw; height: 4.0639cqw; }
  .hero-btn-play .icon { width: 1.8868cqw; height: 1.8868cqw; }

  .hero-actions-secondary { gap: 1.4514cqw; }
  .hero-btn-sub {
    height: 6.9666cqw;
    padding: 0 1.7417cqw;
    font-size: 1.8868cqw;
    gap: 1.1611cqw;
    border-radius: 1.7417cqw;
  }
  .hero-btn-sub-ic .icon { width: 2.3222cqw; height: 2.3222cqw; }

  /* The master already wraps these four to 2+2, but as a wrapping flex row the
     item that ends the first line kept painting its right divider, leaving a
     stray rule hanging in the middle of the card. A two-column grid states the
     2+2 outright: the columns line up, the wrap can never go ragged (3+1) at an
     in-between width, and the divider belongs to the left column only. */
  .hero-features {
    display: grid;
    grid-template-columns: max-content max-content;
    justify-content: start;
    align-items: center;
    column-gap: 1.4514cqw;
    row-gap: 1.1611cqw;
    /* Indent by the secondary button's inner offset so these icons sit on the
       same vertical line as the icons in the buttons directly above. Box
       edges were already flush at 0; it was the icons that read as crooked,
       because a button insets its icon by its own padding and border.
       1.7417cqw is that padding; the +1px is the button border, which does
       not scale. */
    padding-left: calc(1.7417cqw + 1px);
    /* Never wider than the copy column: the columns may shrink below
       max-content, and a label that no longer fits on one line wraps instead
       of overflowing the card. */
    max-width: 100%;
    grid-template-columns: repeat(2, minmax(0, max-content));
  }
  .hero-feat-item { padding: 0; font-size: 1.7417cqw; gap: 1.1611cqw; border-right: 0; min-width: 0; white-space: normal; }
  .hero-feat-item:nth-child(odd) {
    padding-right: 1.4514cqw;
    border-right: 1.5px solid rgba(203, 213, 225, 0.7);
  }
  :root[data-theme="dark"] .hero-feat-item:nth-child(odd) { border-right-color: rgba(255, 255, 255, 0.1); }
  .hero-feat-ic .icon { width: 2.3222cqw; height: 2.3222cqw; }
}

@media (max-width: 1199px) and (min-width: 761px) {
  .today-grid { gap: 18px; }
  .dc-art { width: clamp(160px, 19vw, 200px); }
  .daily-card { padding: 20px; }
  .daily-card .dc-body { padding-right: clamp(150px, 18vw, 188px); }
  .plan-today { padding: 18px; }
  .task, .step { gap: 9px; }
  .step { padding: 9px 11px; min-height: 58px; }
}

@media (max-width: 1024px) {
  .runner-layout { grid-template-columns: 1fr; }
  .navigator { position: static; }
  .home-mock-container { padding: 40px 32px 34px; border-radius: 26px; }
  .home-mock-top { gap: 24px; }
  .home-mock-illu-wrap { max-width: 320px; }
  .home-mock-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; margin-top: 32px; }
  .supported-field-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .vip-showcase, .vip-showcase.has-trio { grid-template-columns: 1fr; }
  /* Stacked under the table, the pair centres rather than hugging the left
     edge of a container twice its width. Three cards get the extra width they
     need to stay side by side. */
  .price-pair { max-width: 620px; margin-inline: auto; }
  .price-pair.is-trio { max-width: 860px; }
  .article-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .admin { grid-template-columns: 1fr; }
  .admin-side {
    position: fixed; inset: 0 auto 0 0; width: 260px; z-index: 220;
    transform: translateX(-100%); transition: transform var(--t);
  }
  .admin-side.open { transform: none; }
  .admin-side-backdrop { position: fixed; inset: 0; background: rgba(10, 18, 40, .5); z-index: 215; }
  /* While the drawer is open the page behind it must not scroll: on a phone a
     page that moves under the reader's finger reads as the drawer having lost
     the content it was covering. */
  body.drawer-open { overflow: hidden; }
  .admin-content { padding: var(--space); }
  .admin-page-head h1 { font-size: 20px; }
}

/* --------------------------------------- Admin tables without a wide screen */
/* An eight-column table does not survive a narrow viewport by scrolling: the
   row an administrator needs is off the right edge and the action buttons with
   it. A table marked .table-stack turns each row into its own block, with the
   column heading carried on each cell in data-label — so the same markup is a
   table on a wide screen and a readable card everywhere else.
   Cells marked .is-secondary drop out entirely: they are the columns there is
   no room for and nobody scrolls sideways to read.
 *
 * The breakpoint is 1024px, the same one at which the sidebar becomes a
 * drawer, and it is deliberately not lower. At 768px the question bank was
 * neither: too wide to fit (799px of table in a 721px box, so edit/duplicate/
 * delete sat past the right edge) and too cramped to read once pinned — the
 * question column collapsed to about 85px. There is no width at which a
 * squeezed eight-column table beats a card, so the two layouts now meet at
 * one boundary with no gap between them. */
/* Five or six tiles in one column is most of a phone screen before the content
   starts, so on a phone they go two-up. Between 700 and 1024 the auto-fit grid
   already fits three or four, which is right. */
@media (max-width: 700px) {
  .admin-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9px; }
  .admin-stats .stat { padding: 11px 12px; }
  .admin-stats .stat .v { font-size: 21px; }
}

@media (max-width: 1024px) {
  .table-stack { display: block; }
  .table-stack thead { display: none; }
  .table-stack tbody, .table-stack tr, .table-stack td { display: block; width: auto; }
  .table-stack tr {
    padding: 11px var(--space); border-bottom: 1px solid var(--border);
  }
  .table-stack tr:last-child { border-bottom: 0; }
  .table-stack td {
    border: 0; padding: 3px 0;
    display: flex; align-items: baseline; gap: var(--space-sm); justify-content: space-between;
    /* .table right-aligns every cell but the first, and on a table with a
       checkbox column the row's title is no longer the first — so it came out
       right-aligned. In a card every line starts at the left edge; the value
       side is pushed right by margin-left:auto on the cell's children. */
    text-align: left;
  }
  .table-stack td.is-secondary { display: none; }
  /* The first cell is the row's title: full width, no label, a little larger. */
  /* The row title: the one cell with no data-label that is not the checkbox
     or the action row. Keyed on data-label rather than :first-child, which
     stopped being the title the moment a checkbox column went in front. */
  .table-stack td:not([data-label]):not(.pick):not(.actions) {
    display: block; padding-bottom: 7px;
  }
  .table-stack td[data-label] { flex-wrap: wrap; }
  .table-stack td[data-label]::before {
    content: attr(data-label);
    flex: 0 0 auto; color: var(--text-subtle); font-size: 12px; font-weight: 600;
  }
  /* A cell with several lines in it (a name over an email, a date over a
     status) keeps them right-aligned against the label rather than letting the
     widest one push out to the edge of the card. */
  .table-stack td[data-label] > * {
    margin-left: auto; text-align: right; min-width: 0; max-width: 100%;
    overflow-wrap: anywhere;
  }
  /* The actions cell becomes a row of full-size targets under the content.
     The sticky right-edge pinning is for the table layout only — here the row
     is a block and there is nothing to scroll past. */
  .table-stack td.actions, .table-stack th.actions {
    position: static; background: none;
  }
  .table-stack td.actions {
    display: flex; justify-content: flex-start; gap: 6px; flex-wrap: wrap;
    padding-top: 9px; white-space: normal;
  }
  .table-stack td.actions::before { content: none; }
  .table-stack td.pick { position: absolute; right: var(--space); margin-top: -2px; }
  .table-stack tr { position: relative; }
}

/* Laptop and below — collapse before the seven links can crowd the account
   actions. The menu remains full-sized inside the dropdown. */
@media (max-width: 1199px) {
  /* The 56px gutter is right for a wide desktop and is most of a phone's
     width, so it steps down with the viewport. */
  .container { padding: 0 32px; }

  .nav-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 42px; height: 42px; margin-left: 0; flex: 0 0 auto;
    background: var(--surface); border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm); color: var(--text); cursor: pointer;
  }
  .main-nav {
    display: none; position: absolute; left: 0; right: 0; top: var(--header-h);
    flex-direction: column; align-items: stretch; gap: 2px; margin: 0;
    padding: 10px; background: var(--surface);
    border-bottom: 1px solid var(--border); box-shadow: var(--shadow);
    max-height: calc(100vh - var(--header-h)); overflow-y: auto;
  }
  /* The panel drops in and its entries follow, so opening the menu reads as a
     movement rather than as a block appearing. */
  .main-nav.open { display: flex; animation: menu-drop 260ms var(--spring); }
  @keyframes menu-drop { from { opacity: 0; transform: translateY(-10px); } }
  .main-nav.open > * { animation: rise 380ms var(--spring) backwards; }
  .main-nav.open > :nth-child(1) { animation-delay: 30ms; }
  .main-nav.open > :nth-child(2) { animation-delay: 60ms; }
  .main-nav.open > :nth-child(3) { animation-delay: 90ms; }
  .main-nav.open > :nth-child(4) { animation-delay: 120ms; }
  .main-nav.open > :nth-child(5) { animation-delay: 150ms; }
  .main-nav.open > :nth-child(6) { animation-delay: 180ms; }
  .main-nav.open > :nth-child(7) { animation-delay: 210ms; }
  .main-nav.open > :nth-child(8) { animation-delay: 240ms; }
  .main-nav.open > :nth-child(9) { animation-delay: 270ms; }
  /* Sized like the menu toggle beside it, so the two read as one pair. */
  .theme-toggle, .icon-btn { width: 40px; height: 40px; border-radius: var(--radius-sm); }
  .main-nav a { padding: 12px 14px; font-size: 15.5px; }
  .header-actions { margin-left: auto; }
  .header-inner { position: relative; }
  .header-cta-vip { height: 40px; padding: 0 15px; font-size: 14px; }

  /* Sign-in sits beside the VIP button here, the same pairing as the desktop,
     rather than being tucked inside the menu. It is the narrower of the two
     controls, so it takes the squeeze: the label loses its padding and steps
     down in size while the VIP call to action keeps its weight. */
  .header-login {
    display: inline-flex; align-items: center;
    height: 40px; padding-inline: 8px;
    font-size: 14px; white-space: nowrap;
  }
  /* Out of the menu, so sign-in is not offered twice on the same screen. */
  .nav-auth-link { display: none; }
}

/* Phone / small tablet. */
@media (max-width: 860px) {
  .account-name { display: none; }
  .footer-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 26px 18px; }
  .footer-grid > :first-child { grid-column: 1 / -1; }
  .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* The closing panel stacks: the drawing keeps its place under the copy at a
     smaller size rather than disappearing, since it is the section's only
     picture. */
  .cta-band { grid-template-columns: 1fr; }
  .cta-art-wrap { justify-content: center; }
  .cta-art { width: 200px; }
}

@media (max-width: 1024px) {
  .home-ranking-shell { padding: 28px 24px 22px; }
  .ranking-following-row {
    grid-template-columns: 44px 38px minmax(130px, 1fr) minmax(112px, .7fr) 96px 66px 16px;
    gap: 9px; padding-inline: 16px;
  }
}

/* The home composition finally stacks once each side would become narrower
   than a comfortable phone card. This keeps the reference two-column rhythm
   through tablets without squeezing the actual question content. */
@media (max-width: 760px) {
  /* The hero is not styled per-phone any more: the <=1199px block above is
     the single composition for every viewport at or below the 768px master,
     so nothing here may reintroduce a phone-specific hero layout. */
  .today-grid { grid-template-columns: 1fr; }
  .daily-card { padding: var(--space); }
  .dc-art { width: 150px; opacity: .5; right: -30px; }
  .daily-card .dc-body { padding-right: 118px; }
  .home-mock-top { grid-template-columns: 1fr; gap: 20px; }
  .home-mock-right { justify-content: center; }
  .home-mock-illu-wrap { max-width: 280px; }

  .home-ranking-head { align-items: flex-start; flex-direction: column; }
  .home-ranking-head .btn { align-self: flex-start; }
  .ranking-following-row {
    grid-template-columns: 40px 36px minmax(0, 1fr) auto;
    grid-template-rows: auto auto; min-height: 76px; column-gap: 9px; row-gap: 2px;
  }
  .ranking-following-row .rank-no,
  .ranking-following-row .avatar { grid-row: 1 / 3; }
  .ranking-following-row .rank-name { grid-column: 3; grid-row: 1; align-self: end; }
  .ranking-following-row .rank-date { display: none; }
  .ranking-following-row .rank-points { grid-column: 3; grid-row: 2; align-self: start; text-align: left; }
  .ranking-following-row .rank-percent { grid-column: 4; grid-row: 1 / 3; align-self: center; }
  .ranking-following-row .rank-go { display: none; }
}

/* The <=400px hero block was removed: its job — stepping the controls down on
   a narrow phone — is now done continuously by the clamps in the <=1199px
   block, and it was also the last rule that changed the copy/artwork split
   (68%) away from the 768px master's 58%. */

@media (max-width: 640px) {
  body { font-size: 15px; }
  .container { padding: 0 14px; }
  .section { padding: var(--space-lg) 0; }
  /* .hero padding is set once in the <=760 block so the phone hero keeps a
     single scale; re-declaring it here only fought that rule. */
  .hero .lead { font-size: 15.5px; }
  .hero-cta .btn { flex: 1 1 100%; }
  .hero-art { max-width: 210px; }
  .hero-main { padding: 20px 16px; border-radius: 18px; }
  .home-hero-benefits { grid-template-columns: 1fr; gap: 0; }
  .home-hero-benefit,
  .home-hero-benefit:nth-child(odd),
  .home-hero-benefit:nth-child(even) { padding: 11px 0; border-left: 0; }
  .home-hero-benefit + .home-hero-benefit { border-top: 1px solid var(--border); }
  .home-fields-section { padding: 18px 0 24px; }
  .home-mock-container { padding: 26px 18px 22px; border-radius: 22px; }
  .home-mock-badge { margin-bottom: 14px; font-size: 12.5px; padding: 6px 14px; }
  .home-mock-title { font-size: 30px; line-height: 1.2; margin-bottom: 12px; }
  .home-mock-desc { font-size: 15px; line-height: 1.55; }
  .home-mock-desc-br { display: none; }
  .home-mock-illu-wrap { max-width: 220px; margin: 0 auto; }
  .home-mock-grid { grid-template-columns: 1fr; gap: 16px; margin-top: 26px; }
  .home-mock-card { padding: 22px 18px 18px; border-radius: 20px; }
  .home-mock-card-icon { width: 68px; height: 68px; border-radius: 18px; margin-bottom: 16px; }
  .home-mock-card-title { font-size: 19px; }
  .home-mock-card-meta { min-height: 0; margin-bottom: 16px; font-size: 13px; }
  .home-mock-card-benefit { font-size: 12.5px; padding: 7px 12px; margin-bottom: 18px; }
  .home-mock-card-cta { height: 50px; font-size: 15px; border-radius: 14px; }
  .home-mock-bottom-wrap { margin-top: 24px; justify-content: center; }
  .home-value-head { margin-bottom: 16px; }
  .home-value-head h2 { font-size: 26px; }
  .supported-field-grid { grid-template-columns: 1fr; gap: 10px; }
  .supported-field-card { min-height: 0; padding: 15px; }
  /* Four figures across a phone leaves four two-character columns; two rows of
     two keeps each number at its full size. */
  .stat-grid { grid-template-columns: 1fr 1fr; gap: 12px; }
  .stat-card { padding: 13px; column-gap: 10px; }
  .stat-card .ic { width: 36px; height: 36px; }
  .stat-card b { font-size: 19px; }
  /* The drawing on the challenge panel becomes a wash behind the copy rather
     than an element beside it — there is no room for both. */
  .dc-art { width: 128px; right: -34px; top: 18%; opacity: .28; }
  .daily-card .dc-body { padding-right: 0; }
  .daily-card .dc-facts { gap: 20px; }
  .today-card, .plan-today { padding: var(--space); }
  .today-mini { grid-template-columns: 1fr; gap: 11px; }
  .price-pair, .price-pair.is-trio { grid-template-columns: 1fr; }
  /* The shared comparison becomes a stacked feature list on phones. The real
     table headers stay in the accessibility tree, while each visible value is
     labelled Free or VIP and never requires horizontal scrolling. */
  .plan-compare .table-wrap { overflow: visible; }
  .plan-compare table { display: block; min-width: 0; width: 100%; }
  .plan-compare thead {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
  }
  .plan-compare tbody { display: grid; }
  .plan-compare tbody tr {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    padding: 12px 13px 10px;
  }
  .plan-compare tbody tr + tr { border-top: 1px solid var(--border); }
  .plan-compare tbody th {
    display: block; grid-column: 1 / -1; width: auto; padding: 0 0 9px;
  }
  .plan-compare tbody td {
    display: block; width: auto; padding: 9px 7px 2px; border-top: 1px solid var(--border);
    text-align: left;
  }
  .plan-compare tbody td.col-plan,
  .plan-compare tbody td.col-vip { width: 100%; }
  .plan-compare tbody tr + tr th { border-top: 0; }
  .plan-compare tbody tr + tr td { border-top: 1px solid var(--border); }
  .plan-compare tbody td::before {
    display: block; margin-bottom: 5px; color: var(--text-subtle);
    font-size: 10.5px; font-weight: 700; letter-spacing: .04em;
  }
  .plan-compare tbody td.col-plan::before { content: 'ฟรี'; }
  .plan-compare tbody td.col-vip::before { content: 'VIP'; color: var(--vip); }
  .plan-compare tbody .col-vip { background: transparent; }
  .plan-compare .yes,
  .plan-compare .no { align-items: flex-start; font-size: 12px; line-height: 1.4; }
  .vip-assurances { grid-template-columns: 1fr; padding: 8px 16px; }
  .vip-assurances > div { justify-content: flex-start; padding: 13px 4px; }
  .vip-assurances > div + div { border-left: 0; border-top: 1px solid var(--border); }
  .price-icon { width: 52px; height: 52px; }
  .article-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cta-band { padding: var(--space-lg) var(--space); border-radius: var(--radius-lg); }
  /* The task list keeps all three columns on a phone; the action shortens to
     its label alone so the row does not wrap. */
  .task { gap: 10px; }
  .task .ic { width: 36px; height: 36px; }
  .step { padding: 10px 12px; gap: 10px; }
  .step .ic { display: none; }
  .card-body, .exam-card, .question-card { padding: var(--space); }
  .question-text { font-size: 18.5px; }
  .choice { padding: 13px 14px; font-size: 16.5px; }
  .runner-body { padding-bottom: 108px; }
  .nav-grid { grid-template-columns: repeat(6, 1fr); }
  .score-ring { width: 148px; height: 148px; }
  .score-ring .v { font-size: 33px; }
  /* The three link groups stay side by side on a phone instead of stacking
     into one long ribbon the user has to scroll past. The brand block above
     them still spans the full width (set at 860px), so this is 1 + 3. */
  .footer-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px 12px; }
  .footer-grid h4 { font-size: 10.5px; margin-bottom: 10px; letter-spacing: .08em; }
  .footer-grid ul { gap: 8px; }
  .footer-grid a, .footer-link-btn { font-size: 12.5px; }
  .section-head { flex-direction: column; align-items: flex-start; }
  .table th, .table td { padding: 10px; }
  /* The runner's top bar carries four things and a phone has room for three.
     The exam name goes first: mid-exam the candidate knows which paper they
     are sitting, whereas the question number, the clock and the way to submit
     are all load-bearing. */
  .runner-title { display: none; }
  .runner-bar-inner { height: 54px; }
  /* The answered tally goes too: the navigator grid already shows which
     questions are done, in a form that is quicker to read than a number. */
  .answered-note { display: none; }

  .home-ranking-shell { padding: 22px 14px 18px; border-radius: 18px; }
  .home-ranking-head h2 { font-size: 28px; }
  .home-ranking-head p { font-size: 14px; }
  .ranking-following-row { padding-inline: 10px; }
  .ranking-reset-note { margin-top: 23px; text-align: center; }

  /* The runner's foot bar keeps its buttons reachable but not oversized.
     Its three controls plus the save indicator do not fit across a phone, so
     the labels shorten, the flag button becomes icon-only and the save state
     drops — the buttons themselves stay full size and fully tappable. */
  .runner-foot .btn { height: 44px; padding: 0 14px; font-size: 14.5px; }
  .runner-foot .btn-lg { height: 46px; }
  .runner-foot .label-full { display: none; }
  .runner-foot .label-short { display: inline; }
  .runner-foot #mark-btn { width: 44px; padding: 0; }
}

/* Two spellings of each label: the full one on a comfortable screen, the short
   one only once space runs out. */
.label-short { display: none; }

/* The phone header keeps one clear paid CTA and the menu toggle. The brand
   gives way in two steps before either action can overflow. */
@media (max-width: 520px) {
  .brand { min-width: 0; }
  .brand-text { min-width: 0; }
  .brand-text b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .brand-text span { display: none; }

  /* The code field and its button stack rather than share a line neither of
     them fits on, and both stay a comfortable thumb target. */
  .redeem-toggle { flex-wrap: wrap; }
  .redeem-hint { flex: 1 1 100%; }
  .redeem-form { flex-direction: column; }
  .redeem-form .form-control,
  .redeem-form .btn { width: 100%; min-height: 48px; }

  /* All three counts stay on one line on a phone. The strip used to wrap the
     last one onto a second row; keeping it inline is what makes it read as a
     single stat bar, so the type and the gaps shrink instead of the row
     breaking. At 360px the three items plus both separators measure well
     inside the footer's width. */
  .footer-stats {
    flex-wrap: nowrap;
    gap: 8px;
    padding: 6px 11px;
    border-radius: 999px;
    max-width: 100%;
    font-size: 11.5px;
  }
  .footer-stats-item { white-space: nowrap; gap: 5px; }
  .footer-stats-label { font-size: 11px; }
}

@media (max-width: 430px) {
  /* The public header has to fit a logo, a menu button and an account control
     on one line, so the wordmark gives way. The admin drawer is 260px of its
     own and has room, so it keeps its name — otherwise the panel opens showing
     nothing but a "DQ" square. */
  .brand-text { display: none; }
  .admin-side .brand-text { display: flex; }
}

@media (max-width: 380px) {
  .container { padding: 0 12px; }
  .nav-grid { grid-template-columns: repeat(5, 1fr); }
}

/* Print — used for a result sheet a candidate wants on paper. */
@media print {
  .site-header, .site-footer, .runner-foot, .runner-bar, .no-print { display: none !important; }
  body { background: #fff; }
  .card { border-color: #ccc; box-shadow: none; break-inside: avoid; }

  /* Reveal-on-scroll waits for a scroll that printing never performs, so every
     section below the fold would come out as a blank rectangle. On paper the
     page is always complete. */
  .js-reveal [data-reveal],
  .js-reveal [data-reveal-group] > *,
  .js-reveal .hero-grid > div > *,
  .js-reveal .hero-visual,
  .js-reveal .hero-card-content > *,
  .js-reveal .hero-card-visual {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
  }
}

/* ============================================================================
   13. MOCK EXAM — จำลองสนามสอบราชการ
   ============================================================================

   Two surfaces live here: the public pages that describe an examination, and
   the runner a candidate sits it in. Both are built only from the tokens above,
   so the dark palette needs nothing restated below and a brand change reaches
   them for free.

   The runner is deliberately plainer than the rest of the site. Under a clock,
   every gradient and every shadow is one more thing that is not the question.
   ========================================================================== */

.ta-r { text-align: right; }

/* ------------------------------------------------------------- Filter chips */
.chip-row {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin-bottom: var(--space-md);
}
.chip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 15px; border-radius: var(--radius-pill);
  font-size: 14px; font-weight: 600; color: var(--text-muted);
  background: var(--surface); border: 1px solid var(--border-strong);
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast);
}
.chip:hover { color: var(--text); border-color: var(--primary-border); text-decoration: none; }
.chip:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--focus-ring); }
.chip.is-active {
  background: var(--primary); border-color: var(--primary); color: var(--primary-contrast);
}
.chip.is-active:hover { color: var(--primary-contrast); }
.chip-count {
  font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums;
  padding: 1px 7px; border-radius: var(--radius-pill);
  background: var(--surface-muted); color: var(--text-subtle);
}
.chip.is-active .chip-count {
  background: rgba(255, 255, 255, .2); color: var(--primary-contrast);
}

/* -------------------------------------------------------------------- Hero */
.mock-hero {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-md); flex-wrap: wrap;
  padding: var(--space-md); margin-bottom: var(--space-md);
  background: var(--surface-raised);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
}
.mock-hero-copy h1 { font-size: 30px; margin: 8px 0 4px; }
.mock-hero-copy .lead { margin: 0; font-size: 16px; }
.mock-hero-points {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 8px;
}
.mock-hero-points li {
  display: flex; align-items: center; gap: 9px;
  font-size: 14px; color: var(--text-muted);
}
.mock-hero-points .icon { color: var(--primary); flex: 0 0 auto; }

.mock-note {
  display: flex; align-items: flex-start; gap: 7px;
  font-size: 12.5px; line-height: 1.7; margin: var(--space) 0 0;
}
.mock-note .icon { margin-top: 3px; flex: 0 0 auto; }

/* ------------------------------------------------------------- Field cards */
.mock-grid {
  display: grid; gap: var(--space);
  grid-template-columns: repeat(auto-fill, minmax(285px, 1fr));
}
.mock-card {
  display: flex; flex-direction: column;
  padding: var(--space-md);
  background: var(--surface-raised);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
  transition: border-color var(--t-fast), box-shadow var(--t-fast), transform var(--t-fast);
}
.mock-card:hover {
  border-color: var(--primary-border); box-shadow: var(--shadow-sm); transform: translateY(-2px);
}
.mock-card-top {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-xs); margin-bottom: var(--space-sm);
}
.mock-card-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; border-radius: var(--radius);
  background: var(--primary-soft); color: var(--primary);
}
.mock-card-title { font-size: 18px; line-height: 1.45; margin: 0 0 4px; }
.mock-card-title a { color: var(--text); }
.mock-card-title a:hover { color: var(--primary); text-decoration: none; }
/* Clamped rather than truncated by PHP: the summary an administrator writes
   stays whole in the database and on the detail page, and only the card limits
   how much of it it shows. */
.mock-card-summary {
  margin: 0 0 var(--space-sm);
  color: var(--text-muted);
  font-size: 13px;
  line-height: 1.6;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Grows to fill the difference between a สนาม with one ภาค and one with three,
   so the facts row and the CTA line up across a row of cards. */
.mock-card-phases {
  display: flex; flex-wrap: wrap; align-content: flex-start; gap: 6px;
  flex: 1 1 auto; margin-bottom: var(--space-sm);
}
.mock-card-phases .pill { padding: 4px 11px; font-size: 12.5px; }

.mock-card-facts {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px; margin: 0 0 var(--space); padding: var(--space-sm) 0;
  border-top: 1px solid var(--hairline); border-bottom: 1px solid var(--hairline);
}
.mock-card-facts > div { text-align: center; min-width: 0; }
.mock-card-facts dt { font-size: 11.5px; color: var(--text-subtle); margin-bottom: 2px; }
.mock-card-facts dd { margin: 0; font-size: 14.5px; font-weight: 700; color: var(--text); }
.mock-card .btn { margin-top: auto; }

/* Mock Exam hub — the public listing has its own visual composition. Keeping
   every override below .mock-page prevents the redesign from leaking into the
   detail pages, runner, shared header or footer. */
.mock-page {
  max-width: 1180px;
  padding-top: 16px;
  /* The shared footer already adds its own 56px of separation, so the page
     stops close to its last section instead of stacking a second gap. */
  padding-bottom: 8px;
}

/* -------------------------------------------------------------------- Hero */
.mock-page .mock-hero {
  position: relative;
  isolation: isolate;
  display: block;
  aspect-ratio: 2048 / 768;
  min-height: 0;
  margin-bottom: 16px;
  padding: 0;
  overflow: hidden;
  background: #eef7ff url('../img/mock-exam-hero-background-v3.webp') center center / cover no-repeat;
  border: 1px solid #dbe7fb;
  border-radius: 16px;
}
.mock-page .mock-hero::before {
  position: absolute;
  z-index: -1;
  left: -80px;
  bottom: -190px;
  width: 650px;
  height: 300px;
  content: "";
  background: rgba(214, 230, 255, .5);
  border-radius: 999px;
  transform: rotate(-13deg);
}
.mock-page .mock-hero-copy {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 45%;
  min-height: 100%;
  min-width: 0;
  padding: 38px 18px 30px 34px;
}
.mock-page .mock-hero-copy .eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 12px;
  color: #1d5eea;
  font-size: 12.5px;
  font-weight: 650;
  line-height: 1;
  background: #edf4ff;
  border: 1px solid #bfd4ff;
  border-radius: var(--radius-pill);
}
.mock-page .mock-hero-copy h1 {
  margin: 0 0 8px;
  color: #0b1735;
  font-size: clamp(64px, 5.8vw, 84px);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: -.04em;
}
.mock-page .mock-hero-copy h1 span { color: #1f63e9; }
.mock-page .mock-hero-copy .lead {
  max-width: none;
  margin: 0 0 3px;
  color: #14213f;
  font-size: clamp(26px, 2.4vw, 32px);
  font-weight: 700;
  line-height: 1.42;
  /* Thai has no hyphenation, so a two-line subtitle otherwise leaves a single
     word stranded on the second line. */
  text-wrap: balance;
}
.mock-hero-description {
  max-width: 50ch;
  margin: 8px 0 0;
  color: #5d6d8c;
  font-size: 18px;
  line-height: 1.65;
}

.mock-visual-paper {
  position: absolute;
  z-index: 2;
  left: 3%;
  top: 22px;
  display: flex;
  flex-direction: column;
  width: 50%;
  height: 192px;
  padding: 23px 21px;
  background: rgba(255, 255, 255, .92);
  border: 1px solid rgba(255, 255, 255, .95);
  border-radius: 14px;
  box-shadow: 0 12px 28px rgba(62, 99, 174, .12);
  transform: rotate(-7deg);
}
.mock-visual-paper strong {
  margin-bottom: 12px;
  color: #294578;
  font-size: 15px;
  letter-spacing: .04em;
}
.mock-visual-rule {
  display: block;
  width: 54%;
  height: 7px;
  margin-bottom: 6px;
  background: #e8eef8;
  border-radius: 99px;
}
.mock-visual-rule.is-long { width: 68%; }
.mock-visual-choice {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 6px;
}
.mock-visual-choice i {
  width: 12px;
  height: 12px;
  border: 1.5px solid #9cb0d3;
  border-radius: 50%;
}
.mock-visual-choice:first-of-type i { border: 4px solid #2b72ef; }
.mock-visual-choice b {
  width: 49%;
  height: 5px;
  background: #dfe7f4;
  border-radius: 99px;
}
.mock-visual-checklist {
  position: absolute;
  z-index: 3;
  top: 19px;
  right: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
  width: 50%;
  padding: 16px 18px;
  color: #3d527a;
  font-size: 12.5px;
  font-weight: 600;
  background: rgba(255, 255, 255, .9);
  border: 1px solid rgba(255, 255, 255, .94);
  border-radius: 14px;
  box-shadow: 0 10px 24px rgba(62, 99, 174, .1);
}
.mock-visual-checklist span {
  display: flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}
.mock-visual-checklist .icon { flex: 0 0 auto; color: #2d72ef; }
.mock-page .mock-visual-stopwatch {
  position: absolute;
  z-index: 4;
  right: 28%;
  bottom: -1px;
  width: 82px;
  height: 82px;
  padding: 6px;
  background: #2367df;
  border: 5px solid #2f75ec;
  border-radius: 50%;
  box-shadow: 0 8px 16px rgba(25, 85, 194, .2);
}
.mock-stopwatch-button {
  position: absolute;
  top: -18px;
  left: 29px;
  width: 20px;
  height: 15px;
  background: #1b5cca;
  border-radius: 4px 4px 2px 2px;
}
.mock-stopwatch-face {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  background:
    repeating-conic-gradient(from 0deg, #9bbdf8 0 1deg, transparent 1deg 30deg),
    #fff;
  border: 3px solid #dce9ff;
  border-radius: 50%;
}
.mock-stopwatch-face::before {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 8px;
  height: 8px;
  content: "";
  background: #1d5fd5;
  border-radius: 50%;
  transform: translate(-50%, -50%);
}
.mock-stopwatch-face i {
  position: absolute;
  left: calc(50% - 1px);
  bottom: 50%;
  width: 2px;
  height: 23px;
  background: #1d5fd5;
  border-radius: 99px;
  transform: rotate(41deg);
  transform-origin: 50% 100%;
}
.mock-visual-motto {
  position: absolute;
  z-index: 2;
  right: 0;
  bottom: 4px;
  color: #73a2ee;
  font-size: 17px;
  font-style: italic;
  line-height: 1.05;
  opacity: .82;
  transform: rotate(-8deg);
}
.mock-visual-motto span { display: block; margin-left: 18px; }

/* --------------------------------------------------------------- VIP strip */
.mock-page .mock-vip-panel {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 16px;
  min-height: 62px;
  margin-bottom: 14px;
  padding: 10px 16px;
  overflow: hidden;
  background: #fffaf1;
  border: 1px solid #f2d6a4;
  border-radius: 13px;
}
.mock-page .mock-vip-panel .vip-mark {
  width: 40px;
  height: 40px;
  color: #fff;
  background: #ef9300;
  border-radius: 11px;
  box-shadow: none;
}
.mock-page .mock-vip-panel .body { flex: none; min-width: 0; }
.mock-page .mock-vip-panel h2 {
  margin: 0 0 2px;
  color: #b55c05;
  font-size: 16px;
  line-height: 1.35;
}
.mock-page .mock-vip-panel p {
  color: #66738d;
  font-size: 12.5px;
  line-height: 1.5;
}
.mock-page .mock-vip-panel .actions { position: relative; z-index: 2; display: block; }
.mock-page .mock-vip-panel .btn-vip {
  gap: 8px;
  min-height: 40px;
  padding: 8px 18px;
  color: #fff;
  font-weight: 700;
  background: #ec8b00;
  border-color: #ec8b00;
  box-shadow: 0 4px 10px rgba(209, 118, 0, .18);
}
.mock-page .mock-vip-panel .btn-vip:hover {
  background: #d97d00;
  border-color: #d97d00;
  transform: translateY(-1px);
}

/* Already a member: a status row, not a second sales pitch. */
.mock-page .mock-vip-panel.is-vip-active {
  background: #fffdf8;
  border-color: #f0e0c2;
}
.mock-page .mock-vip-panel.is-vip-active h2 {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  letter-spacing: -.01em;
}
.mock-page .mock-vip-panel.is-vip-active h2::before {
  width: 7px;
  height: 7px;
  content: "";
  background: #17a44b;
  border-radius: 50%;
  box-shadow: 0 0 0 3px rgba(23, 164, 75, .16);
}
.mock-page .mock-vip-panel.is-vip-active .btn-outline {
  min-height: 40px;
  padding: 8px 16px;
  color: #b55c05;
  font-weight: 650;
  background: #fff;
  border-color: #edd3a5;
}
.mock-page .mock-vip-panel.is-vip-active .btn-outline:hover {
  color: #96490a;
  background: #fff6e8;
  border-color: #e0bd80;
}

/* ------------------------------------------------------------- Field cards */
/* auto-fit, not a fixed 4: with three สนาม a hard four-column track leaves a
   dead cell on the row. The floor of 290px gives three columns inside the
   1180px page and reflows on its own when a fourth สนาม is published. */
.mock-page .mock-grid {
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: 14px;
  align-items: stretch;
}
.mock-page .mock-card {
  position: relative;
  min-width: 0;
  min-height: 318px;
  padding: 16px;
  background: #fff;
  border-color: #e1e8f2;
  border-radius: 14px;
  box-shadow: 0 2px 6px rgba(25, 49, 92, .04);
}
.mock-page .mock-card:hover {
  border-color: #bcd1f7;
  box-shadow: 0 6px 16px rgba(25, 63, 130, .07);
  transform: translateY(-2px);
}
/* The card leads with its identity on one centred axis — icon, name, chips.
   The access badge steps out of the flow so the icon sits on the card's real
   centre rather than on what is left of the row. Everything below stays
   ranged left: a summary and a table of numbers read better that way. */
.mock-page .mock-card-top {
  justify-content: center;
  margin-bottom: 11px;
}
.mock-page .mock-card-icon {
  width: 38px;
  height: 38px;
  color: #2469ec;
  background: #edf4ff;
  border: 1px solid #dce9ff;
  border-radius: 11px;
}
.mock-page .mock-card .badge {
  position: absolute;
  top: 16px;
  right: 16px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 9px;
  font-size: 11.5px;
}

/* 1. The name of the field carries the most weight in the card. */
.mock-page .mock-card-title {
  text-align: center;
  margin: 0 0 5px;
  color: #0c1835;
  font-size: 20px;
  font-weight: 800;
  line-height: 1.32;
  letter-spacing: -.015em;
  text-wrap: balance;
}
.mock-page .mock-card-title a { color: inherit; }

/* 2. The trust chips. Same chip as the ภาค tags below — one shape for the
   whole card — only quieter, so the tags that carry real data stay the
   stronger of the two. `min-height` reserves the one row the two chips take
   at card width, which is what holds the three cards level if a narrower
   viewport wraps one สนาม's chips and not another's. */
.mock-page .mock-card-trust {
  justify-content: center;
  min-height: 27px;
  margin: 0 0 11px;
  padding: 0;
  list-style: none;
}

/* 3. The ภาค tags. Loose enough to read, and they wrap without crowding. */
/* This block absorbs the height difference between a สนาม with one ภาค and one
   with three, which is what keeps the facts row and the CTA on the same line
   across a whole row of cards. */
.mock-page .mock-card-phases {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  align-items: stretch;
  align-content: flex-start;
  gap: 7px;
  margin-bottom: 12px;
}
.mock-card-phases-label {
  color: #8290a8;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .01em;
}
.mock-card-phase-list,
.mock-page .mock-card-trust {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 6px;
}
.mock-page .mock-card .pill {
  padding: 5px 10px;
  color: #40527a;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.45;
  background: #f3f7fd;
  border-color: #e0e9f6;
  border-radius: 8px;
  white-space: normal;
}
/* A claim, not a datum: the same chip on the card's own surface, so it reads
   as a quiet note beside the ภาค tags rather than competing with them. */
.mock-page .mock-card .pill-quiet {
  color: #5b6b89;
  font-size: 12.5px;
  background: #fff;
  border-color: #e4eaf4;
}

/* 4. Marks, clock and number of ภาค as one clearly separated group. */
.mock-page .mock-card-facts {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0;
  margin: 0 0 13px;
  padding: 10px 2px;
  background: #f7f9fd;
  border: 1px solid #e9eef7;
  border-radius: 11px;
}
.mock-page .mock-card-facts > div {
  padding: 0 8px;
  text-align: left;
}
.mock-page .mock-card-facts > div + div { border-left: 1px solid #e3e9f3; }
.mock-page .mock-card-facts dt {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-bottom: 3px;
  color: #78869e;
  font-size: 10px;
  font-weight: 600;
  line-height: 1.25;
  white-space: nowrap;
}
.mock-page .mock-card-facts dt .icon { flex: 0 0 auto; color: #6b83ad; }
.mock-page .mock-card-facts dd {
  margin: 0;
  color: #101e3d;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.3;
  white-space: nowrap;
}

/* 5. The call to action, on the same line in every card of a row. */
.mock-page .mock-card-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  min-height: 46px;
  margin-top: auto;
  padding: 7px 14px;
  color: #fff;
  font-size: 13.5px;
  font-weight: 700;
  background: #1f63e9;
  border-color: #1f63e9;
  border-radius: 10px;
  box-shadow: 0 3px 9px rgba(31, 99, 233, .18);
}
.mock-page .mock-card-cta .icon { flex: 0 0 auto; }
.mock-page .mock-card-cta:hover {
  color: #fff;
  background: #174fc5;
  border-color: #174fc5;
  box-shadow: 0 5px 12px rgba(31, 79, 180, .22);
}
.mock-page .mock-card-cta:focus-visible,
.mock-page .mock-vip-panel .btn:focus-visible,
.mock-prep-link:focus-visible {
  outline: 3px solid rgba(31, 99, 233, .28);
  outline-offset: 2px;
}

/* -------------------------------------------------------------- Disclaimer */
.mock-page .mock-page-note {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin: 14px 0 0;
  padding: 11px 14px;
  color: #4f5d78;
  font-size: 13px;
  line-height: 1.65;
  background: #f6f8fc;
  border: 1px solid #e6ecf5;
  border-radius: 11px;
}
.mock-page .mock-page-note .icon {
  flex: 0 0 auto;
  margin-top: 1px;
  color: #7b8aa5;
}

/* ---------------------------------------------------- Before the exam links */
.mock-prep {
  margin-top: 22px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}
.mock-prep-title {
  margin: 0 0 13px;
  color: #17233f;
  font-size: 16px;
  font-weight: 700;
}
.mock-prep-links {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}
.mock-prep-link {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  padding: 13px 15px;
  background: #fff;
  border: 1px solid #e4eaf4;
  border-radius: 12px;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.mock-prep-link:hover {
  background: #fbfdff;
  border-color: #c3d6f7;
  text-decoration: none;
}
.mock-prep-icon {
  display: inline-flex;
  flex: 0 0 36px;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  color: #2469ec;
  background: #f1f6ff;
  border: 1px solid #dbe8ff;
  border-radius: 10px;
}
.mock-prep-text { min-width: 0; }
.mock-prep-text strong,
.mock-prep-text small { display: block; }
.mock-prep-text strong {
  color: #17233f;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.4;
}
.mock-prep-text small {
  margin-top: 1px;
  color: #6c7a93;
  font-size: 12px;
  line-height: 1.4;
}
.mock-prep-arrow {
  display: inline-flex;
  flex: 0 0 auto;
  margin-left: auto;
  color: #9aa8c0;
  transition: color var(--t-fast), transform var(--t-fast);
}
.mock-prep-link:hover .mock-prep-arrow { color: #1f63e9; transform: translateX(3px); }

/* --------------------------------------------------------------- Responsive */
@media (max-width: 1120px) {
  .mock-page .mock-hero-copy { padding-left: 28px; }
  .mock-page .mock-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .mock-page .mock-card { min-height: 300px; }
  .mock-prep-links { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
}

@media (max-width: 820px) {
  .mock-page .mock-hero {
    /* The copy needs more lines than the art's 2.667 ratio leaves room for
       here, so the hero goes back to growing with its content. */
    aspect-ratio: auto;
    padding: 0;
    background-position: 58% center;
  }
  .mock-page .mock-hero-copy {
    width: 62%;
    min-height: 420px;
    padding: 30px 28px 26px;
    background: linear-gradient(90deg, rgba(255, 255, 255, .96) 0%, rgba(255, 255, 255, .84) 72%, transparent 100%);
  }
  .mock-page .mock-hero-copy h1 { font-size: 56px; }
  .mock-page .mock-hero-copy .lead { max-width: none; }
  .mock-hero-description { max-width: none; }
}

@media (max-width: 640px) {
  .mock-page { padding-top: 12px; padding-bottom: 6px; }
  .mock-page .mock-hero {
    margin-bottom: 12px;
    padding: 0;
    background-position: 64% center;
    border-radius: 15px;
  }
  .mock-page .mock-hero-copy {
    width: 100%;
    min-height: 390px;
    padding: 24px 17px 22px;
    justify-content: flex-start;
    background: linear-gradient(180deg, rgba(255, 255, 255, .97) 0%, rgba(255, 255, 255, .9) 44%, rgba(255, 255, 255, .12) 76%, transparent 100%);
  }
  .mock-page .mock-hero-copy h1 { margin-top: 0; font-size: 48px; }
  .mock-page .mock-hero-copy .lead { font-size: 24px; line-height: 1.35; }
  .mock-hero-description { margin-top: 9px; font-size: 16px; line-height: 1.6; }
  .mock-visual-paper { left: 2%; top: 24px; width: 56%; height: 169px; padding: 20px 17px; }
  .mock-visual-paper strong { font-size: 12px; }
  .mock-visual-checklist { top: 17px; right: -4px; width: 55%; padding: 13px 12px; font-size: 10px; }
  .mock-visual-checklist span { gap: 5px; }
  .mock-page .mock-visual-stopwatch { right: 27%; width: 68px; height: 68px; }
  .mock-stopwatch-button { left: 23px; }
  .mock-visual-motto { display: none; }

  .mock-page .mock-vip-panel {
    grid-template-columns: auto minmax(0, 1fr);
    gap: 11px 13px;
    padding: 14px;
  }
  .mock-page .mock-vip-panel .vip-mark { align-self: start; width: 40px; height: 40px; }
  .mock-page .mock-vip-panel h2 { font-size: 15px; }
  .mock-page .mock-vip-panel p { font-size: 12px; }
  .mock-page .mock-vip-panel .actions { grid-column: 1 / -1; }
  .mock-page .mock-vip-panel .btn {
    width: 100%;
    min-height: 44px;
    justify-content: center;
  }

  .mock-page .mock-grid { grid-template-columns: 1fr; gap: 12px; }
  .mock-page .mock-card { min-height: 0; padding: 16px; }
  .mock-page .mock-card-trust { min-height: 0; }
  .mock-page .mock-card-facts > div { padding-inline: 6px; }
  .mock-page .mock-card-facts dd { font-size: 13.5px; }
  .mock-page .mock-card-cta { min-height: 48px; font-size: 14px; }
  .mock-page .mock-page-note { font-size: 12.5px; padding: 11px 13px; }

  .mock-prep { margin-top: 20px; padding-top: 18px; }
  .mock-prep-links { grid-template-columns: 1fr; gap: 10px; }
}

/* ------------------------------------------------------------- Dark theme */
:root[data-theme="dark"] .mock-page .mock-hero {
  background: var(--surface-raised);
  border-color: var(--border);
}
:root[data-theme="dark"] .mock-page .mock-hero::before { background: rgba(56, 110, 227, .1); }
:root[data-theme="dark"] .mock-page .mock-card,
:root[data-theme="dark"] .mock-visual-paper,
:root[data-theme="dark"] .mock-visual-checklist,
:root[data-theme="dark"] .mock-prep-link {
  background: var(--surface);
  border-color: var(--border);
}
:root[data-theme="dark"] .mock-page .mock-hero-copy h1,
:root[data-theme="dark"] .mock-page .mock-hero-copy .lead,
:root[data-theme="dark"] .mock-prep-title,
:root[data-theme="dark"] .mock-prep-text strong,
:root[data-theme="dark"] .mock-page .mock-card-title,
:root[data-theme="dark"] .mock-page .mock-card-facts dd { color: var(--text); }
:root[data-theme="dark"] .mock-hero-description,
:root[data-theme="dark"] .mock-prep-text small,
:root[data-theme="dark"] .mock-page .mock-page-note { color: var(--text-muted); }
:root[data-theme="dark"] .mock-page .mock-page-note,
:root[data-theme="dark"] .mock-page .mock-card-facts {
  background: var(--surface-muted);
  border-color: var(--border);
}
:root[data-theme="dark"] .mock-page .mock-card-facts > div + div { border-left-color: var(--border); }
:root[data-theme="dark"] .mock-prep-icon,
:root[data-theme="dark"] .mock-page .mock-card-icon {
  color: #93b4fb;
  background: rgba(56, 110, 227, .14);
  border-color: rgba(56, 110, 227, .32);
}
:root[data-theme="dark"] .mock-page .mock-card .pill {
  color: var(--text-muted);
  background: var(--surface-muted);
  border-color: var(--border);
}
:root[data-theme="dark"] .mock-page .mock-card .pill-quiet {
  background: transparent;
  border-color: var(--border);
}
:root[data-theme="dark"] .mock-page .mock-vip-panel { background: #332817; border-color: #725422; }
:root[data-theme="dark"] .mock-page .mock-vip-panel.is-vip-active { background: #2b2417; border-color: #5f4d28; }
:root[data-theme="dark"] .mock-page .mock-vip-panel.is-vip-active .btn-outline {
  color: #f0b967;
  background: transparent;
  border-color: #6d5730;
}


/* ------------------------------------------- Detail: page-wide text scale */
/* The สนาม page is read, not scanned: a candidate works down a blueprint of
   ภาค, ช่วง, วิชา and numbers and compares them. Every size on it therefore
   sits two steps above the site default — +2px throughout, +3px on the page
   title so the top of the page keeps its lead.

   Scoped to .mock-detail-page, which exists only on this page, so the hub, the
   home page and the admin blueprint keep the shared components at their own
   size. One block rather than edits scattered through the mock section: the
   scale is a property of this page and reads as one decision. */
.mock-detail-page { font-size: 17.5px; }

.mock-detail-page .mock-detail-head h1 { font-size: 31px; }
.mock-detail-page .mock-note { font-size: 14.5px; }

.mock-detail-page .mock-overview-facts dt,
.mock-detail-page .mock-phase-facts dt,
.mock-detail-page .mock-major-facts dt { font-size: 13.5px; }
.mock-detail-page .mock-overview-facts dd,
.mock-detail-page .mock-phase-facts dd { font-size: 19px; }
.mock-detail-page .mock-major-facts dd { font-size: 17px; }
.mock-detail-page .mock-session-solo .mock-major-facts dd { font-size: 19px; }
.mock-detail-page .mock-overview-rule,
.mock-detail-page .mock-readiness-note,
.mock-detail-page .mock-readiness-note + .mock-readiness-note { font-size: 15px; }

.mock-detail-page .mock-phase-head h2 { font-size: 21px; }
.mock-detail-page .mock-phase-head p { font-size: 16px; }
.mock-detail-page .mock-phase-rule { font-size: 15.5px; }

.mock-detail-page .mock-session-head { font-size: 16.5px; }
.mock-detail-page .mock-session-no,
.mock-detail-page .mock-session-ref { font-size: 13.5px; }
.mock-detail-page .mock-session-clock,
.mock-detail-page .mock-session-recap { font-size: 15px; }
.mock-detail-page .mock-session-solo-lead { font-size: 16.5px; }

.mock-detail-page .mock-major-name { font-size: 16.5px; }
.mock-detail-page .mock-major-state { font-size: 14px; }
.mock-detail-page .mock-major-head h3 { font-size: 18px; }
.mock-detail-page .mock-major-head p { font-size: 15.5px; }

.mock-detail-page .pill { font-size: 16px; }
.mock-detail-page .mock-session .pill { font-size: 13.5px; }
.mock-detail-page .badge { font-size: 14.5px; }
.mock-detail-page .alert { font-size: 16.5px; }
.mock-detail-page .card-head h2,
.mock-detail-page .card-head h3 { font-size: 19px; }
.mock-detail-page .vip-panel h2,
.mock-detail-page .vip-panel h3 { font-size: 19px; }
.mock-detail-page .vip-panel p { font-size: 15.5px; }
.mock-detail-page .btn { font-size: 17px; }
.mock-detail-page .btn-sm { font-size: 15.5px; }
.mock-detail-page .mock-subject-table th { font-size: 14.5px; }

/* --------------------------------------------------------- Detail: heading */
.mock-detail-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--space); flex-wrap: wrap; margin-bottom: var(--space-sm);
}
.mock-detail-head h1 { font-size: 28px; margin: 0; }

.mock-version-picker { display: flex; align-items: center; gap: 9px; }
.mock-version-picker label { margin: 0; font-size: 13px; color: var(--text-muted); white-space: nowrap; }
.mock-version-picker select {
  height: 40px; padding: 0 13px; font-family: inherit; font-size: 14px;
  color: var(--text); background: var(--surface);
  border: 1px solid var(--border-strong); border-radius: var(--radius);
}
/* ---------------------------------------------------------- Detail: phases */
/* ------------------------------------------------- Exam overview (one สนาม) */
.mock-overview {
  margin-top: var(--space-md);
  padding: var(--space-md);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.mock-overview-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: var(--space-sm) var(--space-md);
  margin: 0;
}
.mock-overview-facts > div { min-width: 0; }
.mock-overview-facts dt {
  margin-bottom: 3px;
  color: var(--text-subtle);
  font-size: 11.5px;
}
.mock-overview-facts dd { margin: 0; font-size: 17px; font-weight: 700; }
.mock-overview-rule {
  display: flex; align-items: flex-start; gap: 8px;
  margin: var(--space) 0 0;
  padding-top: var(--space-sm);
  border-top: 1px solid var(--hairline);
  color: var(--text-muted);
  font-size: 13px; line-height: 1.7;
}
.mock-overview-rule .icon { flex: 0 0 auto; margin-top: 3px; }

/* Which วิชา is holding a ภาค back, and by how many questions. */
.mock-readiness { align-items: flex-start; margin: var(--space-md) var(--space-md) 0; }
.mock-readiness-list {
  margin: 6px 0 0; padding: 0; list-style: none;
  font-size: 13px; line-height: 1.7;
}
.mock-readiness-list li {
  display: flex; flex-wrap: wrap; gap: 4px 10px; justify-content: space-between;
}
.mock-readiness-list li + li { border-top: 1px dashed var(--hairline); padding-top: 4px; margin-top: 4px; }

/* The "choose a วิชาเอก first" state. It is information, not a fault, so it
   keeps the informational tone and never borrows the warning palette. */
.mock-readiness-note { margin: 6px 0 0; font-size: 13px; line-height: 1.7; max-width: 68ch; }
.mock-readiness-note + .mock-readiness-note { margin-top: 3px; font-size: 12.5px; }

/* The chosen วิชาเอก states its own verdict, once there is one to state. */
.mock-major-verdict {
  display: flex; align-items: flex-start; gap: 8px;
  margin: var(--space-sm) 0 0; padding: 9px 12px;
  border: 1px solid var(--hairline); border-radius: var(--radius-sm);
  font-size: 13px; line-height: 1.65;
}
.mock-major-verdict .icon { flex: 0 0 auto; margin-top: 2px; }
.mock-major-verdict.is-ready { border-color: var(--success-border, var(--hairline)); color: var(--text); }
.mock-major-verdict.is-ready .icon { color: var(--success); }
.mock-major-verdict.is-short { border-color: var(--warning-border, var(--hairline)); }
.mock-major-verdict.is-short .icon { color: var(--warning); }
@media (max-width: 600px) {
  .mock-major-verdict { padding: 8px 10px; font-size: 12.5px; }
}

.mock-phase {
  margin-top: var(--space-md);
  background: var(--surface-raised);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  overflow: hidden;
}
.mock-phase-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--space-md); flex-wrap: wrap;
  padding: var(--space-md);
  border-bottom: 1px solid var(--border);
}
.mock-phase-head h2 { font-size: 19px; margin: 0 0 4px; }
.mock-phase-head p { margin: 0; font-size: 14px; max-width: 60ch; }
.mock-phase-facts { display: flex; gap: var(--space-md); margin: 0; flex-wrap: wrap; }
.mock-phase-facts > div { text-align: right; }
.mock-phase-facts dt { font-size: 11.5px; color: var(--text-subtle); margin-bottom: 2px; }
.mock-phase-facts dd { margin: 0; font-size: 17px; font-weight: 700; }

.mock-phase > .alert { margin: var(--space-md); }

/* The unfinished-sitting banner: the first thing in a ภาค that has one, because
   it changes what every button below it means. Carrying on is the primary
   action and keeps the filled blue button; starting over is destructive and
   red, but full size beside it — it is a real choice, not a footnote. */
.mock-resume {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space); flex-wrap: wrap;
  margin: var(--space-md) var(--space-md) 0;
  padding: var(--space) var(--space-md);
  border: 1px solid var(--primary-border); border-left: 3px solid var(--primary);
  border-radius: var(--radius); background: var(--primary-soft);
}
.mock-resume-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.mock-resume-text b { display: flex; align-items: center; gap: 7px; font-size: 15px; }
.mock-resume-text span { font-size: 13px; }
.mock-resume-actions { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
/* The restart form is a flex item beside the resume link, so it must not
   stretch to a full row of its own on desktop. */
.mock-resume-actions form { margin: 0; }

/* One หัวข้อ rule on the admin blueprint: the tick, the name, the จำนวนข้อ
   and the ระดับสมรรถนะ. Four controls fit one line on a desktop and do not on
   a phone, so the wrap lives here rather than in an inline style a media query
   could never override. */
.mock-topic-rule {
  display: flex; align-items: center; gap: 8px;
  flex-wrap: nowrap; margin-bottom: 5px;
}
.mock-topic-rule > label { margin: 0; flex: 1 1 auto; min-width: 0; font-weight: 500; font-size: 13.5px; }
.mock-topic-rule > input[type="checkbox"] { width: 17px; height: 17px; accent-color: var(--primary); flex: 0 0 auto; }
.mock-topic-rule > input[type="number"] { width: 74px; flex: 0 0 auto; }
.mock-topic-rule > select { width: 104px; flex: 0 0 auto; }

@media (max-width: 640px) {
  /* The two numeric controls drop to their own line under the name, which is
     the only part that needs the width. */
  .mock-topic-rule { flex-wrap: wrap; margin-bottom: 11px; }
  .mock-topic-rule > label { flex: 1 1 100%; order: 1; }
  .mock-topic-rule > input[type="checkbox"] { order: 0; }
  .mock-topic-rule > input[type="number"],
  .mock-topic-rule > select { order: 2; flex: 1 1 0; width: auto; }
}

.mock-session-list { padding: var(--space-md); display: flex; flex-direction: column; gap: var(--space); }
/* The ช่วง card is white like every other surface on the page. The one band of
   colour is its header: a blue that travels from the brand blue into indigo
   across the bar, which both names the ช่วง and draws the line between one
   ช่วง and the next without tinting the whole card.
   The gradient is fixed rather than tokenised, so it does not invert with the
   theme — which is why everything on it is plain white and its chips are white
   at low alpha, in both light and dark mode. */
.mock-session {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.mock-session-head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 11px var(--space); font-size: 14.5px;
  background: linear-gradient(135deg, #2563eb 0%, #4f46e5 55%, #6164f0 100%);
  color: #fff;
}
/* The วิชา, which is what the candidate is actually scanning for. */
.mock-session-head b { color: inherit; }
.mock-session-no {
  font-size: 11.5px; font-weight: 700; letter-spacing: .04em;
  padding: 3px 9px; border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, .2);
  color: #fff;
}
.mock-session-clock {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 13px; font-weight: 700; color: #fff;
}
/* The real field's wall-clock time, on the blue header beside the ช่วง number.
   Quieter than the simulated duration — it is context, not something the
   candidate has to obey — so it is white at low alpha rather than a second
   solid chip. */
.mock-session-ref {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px;
  color: #fff;
  font-size: 11.5px; font-weight: 600; white-space: nowrap;
  background: rgba(255, 255, 255, .15);
  border-radius: var(--radius-pill);
}
.mock-subject-table { margin: 0; }
.mock-subject-table th { font-size: 12.5px; }
.mock-subject-table td { vertical-align: top; }

/* A ช่วง with exactly one วิชา: the session header above already names it, so
   this is a flat fact row instead of a one-row table repeating that name. */
.mock-session-solo { padding: var(--space); }
.mock-session-solo-lead { margin: 0 0 var(--space-sm); font-size: 14.5px; }

/* The way into one ช่วง on its own — the main action of the ช่วง, so it is a
   filled button, but at btn-sm against the full-size Full Mock button in the
   ภาค footer, which stays the primary way through the whole ภาค.
   The strip is the lighter of the two tints: the numbers on it are a recap,
   not a heading. */
.mock-session-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-sm) var(--space); flex-wrap: wrap;
  padding: 10px var(--space);
  background: var(--primary-soft);
  border-top: 1px solid var(--border);
}
.mock-session-recap {
  display: flex; align-items: baseline; gap: 4px 10px; flex-wrap: wrap;
  min-width: 0; font-size: 13px;
}
.mock-session-recap-score { font-size: 13px; color: var(--text-muted); }
.mock-session-recap-score b { font-size: 15px; color: var(--text); margin-left: 3px; }
.mock-session-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* Four ways in is three too many to guess between, so the ภาค footer spells
   out what each does to the clock. */
.mock-mode-legend {
  margin: var(--space-sm) 0 0; font-size: 12.5px; line-height: 1.7;
  padding: 0 var(--space-md) var(--space-md);
}
.mock-mode-legend b { color: var(--text-muted); font-weight: 600; }

.mock-phase-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space); flex-wrap: wrap;
  padding: var(--space) var(--space-md) var(--space-md);
  border-top: 1px solid var(--hairline);
}
.mock-phase-rule {
  display: flex; align-items: center; gap: 8px;
  margin: 0; font-size: 13.5px;
}
.mock-phase-actions { display: flex; gap: 8px; flex-wrap: wrap; }
/* The two practice routes sit beside the filled Full Mock button. They stay
   outline — secondary by rank — but in the blue the rest of the ภาค is drawn
   in, so the footer reads as one set of choices rather than three unrelated
   controls. */
.mock-phase-actions .btn-outline { --btn-fg: var(--primary); --btn-border: var(--primary-border); }
.mock-phase-actions .btn-outline:hover { --btn-bg: var(--primary-soft); --btn-border: var(--primary); }

/* ------------------------------------------------------------- The briefing */
.mock-brief-head { margin-bottom: var(--space-md); }
.mock-brief-head h1 { font-size: 26px; margin: 8px 0 4px; }
.mock-brief-head .lead { margin: 0; }

.mock-choice-list { display: flex; flex-direction: column; gap: 9px; }
.mock-choice-grid {
  display: grid; gap: 9px;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
}
.mock-choice {
  display: flex; flex-direction: column; gap: 3px;
  padding: 12px var(--space); border-radius: var(--radius);
  border: 1px solid var(--border-strong); background: var(--surface);
  color: var(--text); font-size: 14.5px;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.mock-choice:hover { border-color: var(--primary-border); background: var(--surface-hover); text-decoration: none; }
.mock-choice .text-subtle { font-size: 12.5px; }
/* A ช่วง that is not open yet is listed rather than hidden — a candidate should
   see it is coming — so it needs to look unavailable without being invisible. */
.mock-choice.is-disabled {
  border-style: dashed; border-color: var(--border);
  background: var(--surface-muted); color: var(--text-muted); cursor: not-allowed;
}
.mock-choice.is-selected {
  border-color: var(--primary); background: var(--primary-soft);
  box-shadow: inset 0 0 0 1px var(--primary);
}

.mock-summary {
  display: grid; gap: var(--space-sm) var(--space-md); margin: 0;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.mock-summary > div { min-width: 0; }
.mock-summary dt { font-size: 12px; color: var(--text-subtle); margin-bottom: 3px; }
.mock-summary dd { margin: 0; font-size: 15.5px; font-weight: 700; color: var(--text); }

.mock-brief-sessions {
  display: flex; flex-direction: column; gap: 9px;
  margin-top: var(--space); padding-top: var(--space);
  border-top: 1px solid var(--hairline);
}
.mock-brief-session { display: flex; align-items: flex-start; gap: 11px; }
.mock-brief-session .n {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: var(--radius-pill);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12.5px; font-weight: 700;
  background: var(--primary-soft); color: var(--primary);
}
.mock-brief-session b { display: block; font-size: 14.5px; }
.mock-brief-session .text-subtle { font-size: 12.5px; }

.mock-rules { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.mock-rules li {
  display: flex; align-items: flex-start; gap: 10px;
  font-size: 14px; color: var(--text-muted); line-height: 1.65;
}
.mock-rules .icon { margin-top: 2px; flex: 0 0 auto; color: var(--primary); }

/* --------------------------------------------------------- Result: topics */
.mock-topic-list { display: flex; flex-direction: column; gap: 13px; margin-top: var(--space); }
.mock-topic-row .top {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--space-sm); margin-bottom: 5px; font-size: 14px;
}
.mock-topic-row .top .num { white-space: nowrap; }

/* ---------------------------------------------------------- Major selector */
/* Choosing a วิชาเอก is a required step, not a preference, so the panel is
   tinted to separate it from the structure table above it — a plain white block
   inside a white card reads as more information rather than as something to do. */
.mock-major-panel {
  margin: 0 var(--space-md) var(--space-md);
  padding: var(--space);
  background: var(--primary-soft);
  border: 1px solid var(--primary-border);
  border-radius: var(--radius);
  scroll-margin-top: calc(var(--header-h) + var(--space));
}
.mock-major-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--space); flex-wrap: wrap; margin-bottom: var(--space-sm);
}
.mock-major-head h3 { font-size: 16px; margin: 0 0 3px; }
.mock-major-head p { margin: 0; font-size: 13.5px; max-width: 62ch; }

.mock-major-current {
  padding: 7px 14px; border-radius: var(--radius-sm);
  background: var(--surface); border: 1px solid var(--primary-border);
  white-space: nowrap;
}
.mock-major-current .k { display: block; font-size: 11px; color: var(--text-subtle); }
.mock-major-current b { font-size: 15px; color: var(--primary); }

.mock-major-facts {
  display: grid; gap: var(--space-sm) var(--space);
  grid-template-columns: repeat(auto-fit, minmax(112px, 1fr));
  margin: 0 0 var(--space); padding: var(--space-sm) var(--space);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.mock-major-facts > div { min-width: 0; }
/* Inside a ช่วง the card is already the frame, so the figures drop theirs and
   are separated by a rule and by type alone. */
.mock-session-solo .mock-major-facts {
  padding: var(--space) 0 0;
  background: none;
  border: none;
  border-top: 1px solid var(--hairline);
  border-radius: 0;
}
.mock-session-solo .mock-major-facts dd { font-size: 17px; }
.mock-major-facts dt { font-size: 11.5px; color: var(--text-subtle); margin-bottom: 2px; }
.mock-major-facts dd { margin: 0; font-size: 15px; font-weight: 700; color: var(--text); }

.mock-major-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

.mock-major-grid {
  display: grid; gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
}

/* Both states share the frame so the list reads as one set of options; only the
   surface, the border and the accent say which of them is a way forward. */
.mock-major {
  display: flex; flex-direction: column; gap: 3px;
  padding: 11px 14px; border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong); background: var(--surface);
  transition: border-color var(--t-fast), box-shadow var(--t-fast), background var(--t-fast);
}
.mock-major-name { font-size: 14.5px; font-weight: 600; color: var(--text); }
.mock-major-state {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12px; color: var(--text-muted);
}

.mock-major.is-available { border-color: var(--primary-border); }
.mock-major.is-available .mock-major-state { color: var(--success); }
.mock-major.is-available:hover {
  border-color: var(--primary); background: var(--surface);
  box-shadow: inset 0 0 0 1px var(--primary); text-decoration: none;
}
.mock-major.is-available:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--focus-ring); }

/* Muted by surface and border, never by opacity: a candidate has to be able to
   read which subject is coming, which is the entire reason it is on screen. */
.mock-major.is-soon {
  background: var(--surface-muted); border-style: dashed; cursor: default;
}
.mock-major.is-soon .mock-major-name { color: var(--text-muted); font-weight: 500; }
/* The words stay at text-muted, which clears AA at this size; the amber is
   carried by the icon alone. Warning-on-muted is only about 3:1, which is
   fine for a chip and not fine for the label a reader has to actually
   read. */
.mock-major.is-soon .mock-major-state { color: var(--text-muted); }
.mock-major.is-soon .mock-major-state .icon { color: var(--warning); }

.mock-brief-label {
  margin: var(--space) 0 0; padding-top: var(--space);
  border-top: 1px solid var(--hairline);
  font-size: 12.5px; font-weight: 700; color: var(--text-muted);
}
.mock-brief-label + .mock-brief-sessions { margin-top: 9px; padding-top: 0; border-top: none; }

/* ============================================================================
   THE RUNNER
   ========================================================================== */

.mock-body { background: var(--background); }

.mrun { display: flex; flex-direction: column; min-height: 100vh; min-height: 100dvh; }

/* ----------------------------------------------------------------- Top bar */
.mrun-bar {
  position: sticky; top: 0; z-index: 40;
  background: var(--surface); border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow-xs);
}
.mrun-bar-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space); flex-wrap: nowrap;
  max-width: var(--container); margin: 0 auto;
  padding: 11px var(--space);
}
.mrun-id { min-width: 0; }
.mrun-exam {
  display: block; font-size: 14.5px; line-height: 1.3;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mrun-session {
  display: block; font-size: 12.5px; color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mrun-meters { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }
.mrun-count { font-size: 13.5px; color: var(--text-muted); white-space: nowrap; }
.mrun-count b { font-size: 16px; color: var(--text); }
.mrun-count .sep { margin: 0 2px; color: var(--text-subtle); }

/* ตอบแล้ว / ยังไม่ตอบ / ทำเครื่องหมาย, in the bar itself. Hidden below the
   tablet breakpoint, where the footer and the navigator already carry them and
   the bar has to keep room for the clock. */
.mrun-stats { display: flex; align-items: center; gap: 10px; white-space: nowrap; }
.mrun-stats > span {
  display: inline-flex; align-items: baseline; gap: 4px;
  padding: 3px 9px; border-radius: var(--radius-pill);
  color: var(--text-muted); font-size: 12px; font-weight: 600;
  background: rgba(255, 255, 255, .06);
}
.mrun-stats b { font-size: 13.5px; font-variant-numeric: tabular-nums; }
.mrun-stats .is-ok b { color: var(--success); }
.mrun-stats .is-bad b { color: var(--warning); }
.mrun-stats .is-warn b { color: var(--info, var(--primary)); }
.mrun-stats > span[hidden] { display: none !important; }
@media (max-width: 860px) { .mrun-stats { display: none; } }

/* The clock escalates on its own, so it is noticed without being watched. */
.mrun-timer {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 13px; border-radius: var(--radius);
  font-size: 16px; font-weight: 700; font-variant-numeric: tabular-nums;
  background: var(--surface-muted); border: 1px solid var(--border-strong);
  color: var(--text);
}
.mrun-timer.warning { background: var(--warning-soft); border-color: var(--warning-border); color: var(--warning); }
.mrun-timer.danger  { background: var(--danger-soft);  border-color: var(--danger-border);  color: var(--danger); }

.mrun-progress { height: 3px; background: var(--surface-muted); }
.mrun-progress > span {
  display: block; height: 100%; background: var(--primary);
  transition: width var(--t);
}

/* ------------------------------------------------------------------- Paper */
.mrun-body {
  flex: 1 1 auto;
  display: grid; grid-template-columns: minmax(0, 1fr) 300px;
  gap: var(--space-md); align-items: start;
  max-width: var(--container); width: 100%; margin: 0 auto;
  padding: var(--space-md) var(--space) 96px;
}

.mrun-paper { min-width: 0; }
.mrun-q {
  padding: var(--space-md);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-xs);
}
.mrun-q-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: var(--space); }
.mrun-q-no {
  font-size: 12.5px; font-weight: 700;
  padding: 3px 11px; border-radius: var(--radius-pill);
  background: var(--surface-muted); color: var(--text-muted);
}
.mrun-q-text {
  font-size: 17px; line-height: 1.85; color: var(--text);
  margin: 0 0 var(--space-md); white-space: pre-line;
}

.mrun-choices { display: flex; flex-direction: column; gap: 10px; }
.mrun-choice {
  display: flex; align-items: flex-start; gap: 13px; width: 100%;
  padding: 14px var(--space); text-align: left;
  font-family: inherit; font-size: 15.5px; line-height: 1.7; color: var(--text);
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius); cursor: pointer;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.mrun-choice:hover { border-color: var(--primary-border); background: var(--surface-hover); }
.mrun-choice:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--focus-ring); }
.mrun-choice .k {
  flex: 0 0 auto; width: 28px; height: 28px; border-radius: var(--radius-pill);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 13.5px; font-weight: 700;
  background: var(--surface-muted); color: var(--text-muted);
  transition: background var(--t-fast), color var(--t-fast);
}
.mrun-choice .t { min-width: 0; }
.mrun-choice.is-selected {
  border-color: var(--primary); background: var(--primary-soft);
  box-shadow: inset 0 0 0 1px var(--primary);
}
.mrun-choice.is-selected .k { background: var(--primary); color: var(--primary-contrast); }

/* --------------------------------------------------------------- Navigator */
.mrun-nav {
  position: sticky; top: calc(var(--header-h) + var(--space));
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); overflow: hidden;
}
.mrun-nav-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px var(--space); border-bottom: 1px solid var(--border);
  background: var(--surface-muted);
}
.mrun-nav-head h2 {
  display: flex; align-items: center; gap: 7px;
  font-size: 14px; margin: 0;
}
.mrun-nav-close { display: none; }

.mrun-nav-body { padding: var(--space); max-height: 52vh; overflow-y: auto; }
.mrun-nav-group + .mrun-nav-group { margin-top: var(--space); }
.mrun-nav-group h3 {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  font-size: 12.5px; font-weight: 700; color: var(--text-muted);
  margin: 0 0 8px;
}
.mrun-nav-group h3 span { font-size: 11.5px; font-weight: 500; color: var(--text-subtle); }

.mrun-nav-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(38px, 1fr)); gap: 6px; }
.mrun-nav-grid button {
  height: 38px; border-radius: var(--radius-sm);
  font-family: inherit; font-size: 13.5px; font-weight: 600;
  font-variant-numeric: tabular-nums;
  background: var(--surface); color: var(--text-muted);
  border: 1px solid var(--border-strong); cursor: pointer;
  transition: all var(--t-fast); position: relative;
}
.mrun-nav-grid button:hover { border-color: var(--primary-border); color: var(--text); }
.mrun-nav-grid button.is-answered {
  background: var(--primary-soft); border-color: var(--primary-border); color: var(--primary);
}
.mrun-nav-grid button.is-marked::after {
  content: ""; position: absolute; top: 3px; right: 3px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--warning);
}
.mrun-nav-grid button.is-current {
  background: var(--primary); border-color: var(--primary); color: var(--primary-contrast);
}

.mrun-legend {
  display: flex; flex-wrap: wrap; gap: 5px 13px;
  padding: 11px var(--space); border-top: 1px solid var(--border);
  font-size: 11.5px; color: var(--text-subtle);
}
.mrun-legend span { display: inline-flex; align-items: center; gap: 6px; }
.mrun-legend i {
  width: 11px; height: 11px; border-radius: 3px;
  border: 1px solid var(--border-strong); background: var(--surface);
}
.mrun-legend i.is-answered { background: var(--primary-soft); border-color: var(--primary-border); }
.mrun-legend i.is-current { background: var(--primary); border-color: var(--primary); }
.mrun-legend i.is-marked { background: var(--warning); border-color: var(--warning); }

.mrun-nav-scrim { display: none; }

/* -------------------------------------------------------------- Bottom bar */
.mrun-foot {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
  background: var(--surface); border-top: 1px solid var(--border);
  box-shadow: 0 -2px 14px rgba(12, 23, 48, .07);
  padding-bottom: env(safe-area-inset-bottom);
}
.mrun-foot-inner {
  display: flex; align-items: center; gap: 8px;
  max-width: var(--container); margin: 0 auto;
  padding: 11px var(--space);
}
.mrun-mark.is-marked { color: var(--warning); }
.mrun-save { font-size: 12.5px; color: var(--text-subtle); white-space: nowrap; }
.mrun-save.is-ok { color: var(--success); }
.mrun-save.is-bad { color: var(--danger); }
.mrun-nav-open { display: none; }

/* ----------------------------------------------------------- Submit dialog */
.mrun-tally {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 9px; margin-bottom: var(--space);
}
.mrun-tally-cell {
  text-align: center; padding: 12px 8px; border-radius: var(--radius);
  background: var(--surface-muted); border: 1px solid var(--border);
}
.mrun-tally-cell b { display: block; font-size: 22px; line-height: 1.2; color: var(--text); }
.mrun-tally-cell span { font-size: 12px; color: var(--text-muted); }
.mrun-tally-cell.is-ok   { background: var(--success-soft); border-color: var(--success-border); }
.mrun-tally-cell.is-ok b { color: var(--success); }
.mrun-tally-cell.is-bad  { background: var(--danger-soft);  border-color: var(--danger-border); }
.mrun-tally-cell.is-bad b { color: var(--danger); }
.mrun-tally-cell.is-warn { background: var(--warning-soft); border-color: var(--warning-border); }
.mrun-tally-cell.is-warn b { color: var(--warning); }

/* ============================================================================
   MOCK EXAM — TABLET AND PHONE
   ============================================================================
   The navigator becomes a sheet rather than a narrower column: a 100-question
   grid squeezed into a phone-width sidebar is unusable, and pushed below the
   paper it is never found. The footer keeps the actions a thumb needs and drops
   the words around them.
   ========================================================================== */

@media (max-width: 1060px) {
  .mrun-body { grid-template-columns: minmax(0, 1fr); padding-bottom: 88px; }

  .mrun-nav {
    position: fixed; left: 0; right: 0; bottom: 0; top: auto; z-index: 60;
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    border: 1px solid var(--border); border-bottom: none;
    box-shadow: 0 -8px 40px rgba(12, 23, 48, .22);
    transform: translateY(101%);
    transition: transform var(--t-slow);
    max-height: 82vh; display: flex; flex-direction: column;
  }
  .mrun-nav.is-open { transform: translateY(0); }
  .mrun-nav-head { padding-top: 15px; }
  .mrun-nav-close { display: inline-flex; }
  .mrun-nav-body { max-height: none; flex: 1 1 auto; }
  .mrun-legend { padding-bottom: calc(11px + env(safe-area-inset-bottom)); }

  /* :not([hidden]) matters: a bare `display: block` here would beat the
     user-agent rule behind the hidden attribute and leave the scrim over
     the paper on every phone. */
  .mrun-nav-scrim:not([hidden]) {
    display: block; position: fixed; inset: 0; z-index: 55;
    background: rgba(10, 20, 48, .45);
  }
  .mrun-nav-open { display: inline-flex; }
}

@media (max-width: 640px) {
  .mock-hero { padding: var(--space); }
  .mock-hero-copy h1 { font-size: 25px; }
  .mock-hero-points { flex-direction: row; flex-wrap: wrap; gap: 6px 14px; }
  .mock-hero-points li { font-size: 12.5px; }

  .mock-phase-facts { gap: var(--space); }
  .mock-phase-facts > div { text-align: left; }
  .mock-phase-head, .mock-session-list, .mock-phase-foot { padding-left: var(--space); padding-right: var(--space); }
  .mock-phase-actions { width: 100%; }
  .mock-phase-actions .btn { flex: 1 1 auto; justify-content: center; }

  /* The ช่วง footer stacks: the recap reads as a line of its own and the
     actions get the full width, so "เริ่มสอบช่วงนี้" is a full-size tap target
     rather than a 90px button squeezed beside a score. */
  /* Both actions go full width and stack. Two half-width buttons where one of
     them is destructive is exactly where a thumb lands on the wrong one. */
  .mock-resume { margin-left: var(--space); margin-right: var(--space); flex-direction: column; align-items: stretch; }
  .mock-resume-actions { flex-direction: column; align-items: stretch; width: 100%; }
  .mock-resume-actions .btn { width: 100%; justify-content: center; }

  /* The header wraps at this width; the flex spacer would take a whole row of
     its own, so the clock claims the free space directly instead. */
  .mock-session-head .spacer { display: none; }
  .mock-session-clock { margin-left: auto; }

  .mock-session-foot { flex-direction: column; align-items: stretch; gap: var(--space-sm); }
  .mock-session-actions { width: 100%; }
  .mock-session-actions .btn { flex: 1 1 auto; justify-content: center; height: 42px; }
  .mock-mode-legend { padding-left: var(--space); padding-right: var(--space); }

  /* The subject table becomes stacked rows: four columns at 360px is a
     horizontal scroll nobody performs. */
  .mock-subject-table thead { display: none; }
  .mock-subject-table tr { display: block; padding: 11px var(--space); border-bottom: 1px solid var(--hairline); }
  .mock-subject-table td { display: flex; justify-content: space-between; gap: var(--space); border: none; padding: 3px 0; }
  /* The name cell carries a heading and a description, so it stacks; only
     the value cells become label-and-number rows. */
  .mock-subject-table td:first-child { display: block; padding-bottom: 6px; }
  .mock-subject-table td.ta-r { text-align: left; }
  .mock-subject-table td:nth-child(2)::before { content: "คะแนน"; font-size: 12.5px; color: var(--text-subtle); }
  .mock-subject-table td:nth-child(3)::before { content: "จำนวนข้อสอบ"; font-size: 12.5px; color: var(--text-subtle); }
  .mock-subject-table td:nth-child(4)::before { content: "เกณฑ์ผ่าน"; font-size: 12.5px; color: var(--text-subtle); }

  .mrun-bar-inner { padding: 9px 12px; gap: 10px; }
  .mrun-exam { font-size: 13px; }
  .mrun-session { font-size: 11.5px; }
  .mrun-count { display: none; }
  .mrun-timer { font-size: 15px; padding: 6px 10px; }
  .mrun-submit-open .label-full { display: none; }

  .mrun-body { padding: var(--space) 12px 84px; }
  .mrun-q { padding: var(--space); border-radius: var(--radius); }
  .mrun-q-text { font-size: 16px; }
  .mrun-choice { padding: 12px 13px; font-size: 15px; gap: 11px; }

  /* Prev, mark, navigator and next all stay; only their words go. */
  .mrun-foot-inner { padding: 9px 12px; gap: 6px; }
  .mrun-foot-inner .label-full { display: none; }
  .mrun-save { display: none; }
  .mrun-foot .btn { padding-left: 13px; padding-right: 13px; }
  .mrun-next { flex: 1 1 auto; justify-content: center; }

  .mrun-tally-cell b { font-size: 19px; }
}

/* The runner chrome is not printed; a result sheet is. */
@media print {
  .mrun-bar, .mrun-foot, .mrun-nav, .mrun-nav-scrim { display: none !important; }
}

@media (max-width: 640px) {
  .mock-major-panel { margin-left: var(--space); margin-right: var(--space); }
  .mock-major-grid { grid-template-columns: 1fr 1fr; }
  .mock-major-head { gap: var(--space-sm); }
}

/* ------------------------------------------------ Exam catalogue and responsive filter */
.exam-catalogue { padding-top: 18px; }
.exam-catalogue-head {
  position: relative; overflow: hidden;
  display: grid; grid-template-columns: minmax(0, .96fr) minmax(0, 1.04fr);
  align-items: center; gap: 12px 36px; min-height: 294px;
  padding: 20px 28px 24px; margin-bottom: 24px;
  border: 1px solid var(--primary-border); border-radius: 24px;
  background:
    radial-gradient(circle at 52% 16%, rgba(123, 97, 255, .09), transparent 27%),
    radial-gradient(circle at 84% 92%, rgba(37, 99, 235, .09), transparent 31%),
    linear-gradient(135deg, var(--surface), color-mix(in srgb, var(--primary-soft) 42%, var(--surface)));
  box-shadow: 0 14px 36px rgba(35, 68, 132, .07);
}
.exam-catalogue-head::after {
  content: ""; position: absolute; left: 48%; bottom: 22px; width: 7px; height: 7px; border-radius: 50%;
  color: rgba(95, 86, 232, .14); box-shadow: 0 0 0 1px currentColor, 30px -22px 0 -2px currentColor, 58px 4px 0 -2px currentColor;
  pointer-events: none;
}
/* VIP members lose the upsell panel, which frees the right half of the card —
   the only state where the artwork has somewhere to go. The copy is held to
   the illustration's blank left side so the owl is never written over. */
.exam-catalogue-head.is-vip-user {
  grid-template-columns: 1fr;
  min-height: 0;
  aspect-ratio: 2048 / 768;
  padding-right: 52%;
  background: url('../img/exams-hero-background-v2.webp') center / cover no-repeat;
}
.exam-catalogue-head.is-vip-user::after { display: none; }
.exam-catalogue-head.is-vip-user .exam-catalogue-intro { max-width: none; }
.exam-catalogue-intro { min-width: 0; }
.exam-catalogue-intro .eyebrow {
  min-height: 34px; padding: 5px 14px; margin: 0 0 10px;
  border-color: rgba(103, 80, 229, .14); background: rgba(113, 91, 231, .1);
  color: #4d46cf; font-size: 12.5px;
}
.exam-catalogue-intro h1 { margin: 0; font-size: clamp(42px, 3.2vw, 48px); font-weight: 800; line-height: 1.08; letter-spacing: -.035em; color: var(--text); }
.exam-catalogue-intro > p { max-width: 620px; margin: 13px 0 0; color: var(--text-muted); font-size: 15px; line-height: 1.62; }
.exam-catalogue-summary {
  display: grid; grid-template-columns: 1fr 1fr; width: min(100%, 350px); min-height: 68px;
  margin-top: 14px; padding: 8px; border: 1px solid var(--border); border-radius: 16px;
  background: color-mix(in srgb, var(--surface) 92%, transparent); box-shadow: var(--shadow-sm);
}
.exam-stat { display: flex; align-items: center; gap: 10px; padding: 0 11px; }
.exam-stat + .exam-stat { border-left: 1px solid var(--border); }
.exam-stat-icon { display: grid; place-items: center; width: 38px; height: 38px; flex: 0 0 auto; border-radius: 12px; background: var(--primary-soft); color: #4d46cf; }
.exam-stat-icon .icon { width: 19px; height: 19px; }
.exam-stat:nth-child(2) .exam-stat-icon { background: rgba(37, 99, 235, .09); color: var(--primary); }
.exam-stat > span:last-child { display: grid; line-height: 1.05; }
.exam-stat b { color: #4d46cf; font-size: 23px; font-weight: 800; }
.exam-stat small { margin-top: 4px; color: var(--text-muted); font-size: 11.5px; white-space: nowrap; }

/* The summary is the one number a visitor actually came for, so on wide screens
   it is scaled up 2x. Only here: below 1181 the copy already spans the whole
   card and a box this size would swamp the heading it sits under. */
@media (min-width: 1181px) {
  .exam-catalogue-head { padding-left: 48px; }
  .exam-catalogue-summary {
    width: 100%; max-width: 700px; min-height: 136px;
    margin-top: 28px; padding: 16px; border-radius: 22px;
  }
  .exam-stat { gap: 20px; padding: 0 22px; }
  .exam-stat-icon { width: 76px; height: 76px; border-radius: 24px; }
  .exam-stat-icon .icon { width: 38px; height: 38px; }
  .exam-stat b { font-size: 46px; }
  .exam-stat small { margin-top: 8px; font-size: 20px; }
}

.exam-vip-compact {
  position: relative; isolation: isolate; overflow: hidden;
  display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(170px, .8fr); align-items: stretch;
  width: 100%; min-height: 220px; border: 1px solid rgba(94, 121, 255, .42); border-radius: 20px;
  background:
    radial-gradient(circle at 76% 22%, rgba(104, 90, 255, .55), transparent 35%),
    radial-gradient(circle at 30% 115%, rgba(37, 99, 235, .48), transparent 52%),
    linear-gradient(135deg, #101d63 0%, #182f94 56%, #273cc4 100%);
  color: #fff; box-shadow: 0 12px 26px rgba(28, 44, 132, .17);
}
.exam-vip-compact::before { content: ""; position: absolute; inset: 0; z-index: -1; background: radial-gradient(circle at 14% 22%, rgba(255,255,255,.08) 0 2px, transparent 3px), radial-gradient(circle at 54% 18%, rgba(255,211,91,.7) 0 2px, transparent 3px); background-size: 76px 70px, 132px 108px; opacity: .75; }
.exam-vip-content { position: relative; z-index: 2; display: flex; align-items: flex-start; flex-direction: column; justify-content: center; min-width: 0; padding: 20px 0 19px 25px; }
.exam-vip-icon { display: inline-flex; color: #ffd35b; filter: drop-shadow(0 4px 6px rgba(255, 193, 38, .24)); }
.exam-vip-icon .icon { width: 27px; height: 27px; }
.exam-vip-compact h2 { margin: 6px 0 0; color: #fff; font-size: clamp(20px, 1.65vw, 25px); line-height: 1.25; letter-spacing: -.02em; }
.exam-vip-compact h2 em { color: #ffd45e; font-style: normal; }
.exam-vip-compact p { margin: 9px 0 0; color: rgba(238, 242, 255, .82); font-size: 11.5px; line-height: 1.55; }
.exam-vip-cta {
  min-width: 188px; min-height: 44px; margin-top: 13px; padding: 0 22px;
  border: 1px solid rgba(255, 236, 157, .82); border-radius: 12px;
  background: linear-gradient(135deg, #ffe27d, #f7b92d); color: #111d4b;
  box-shadow: 0 7px 16px rgba(244, 181, 42, .22); font-size: 14px; font-weight: 800;
}
.exam-vip-cta:hover { background: linear-gradient(135deg, #ffea9d, #f3ae17); color: #081435; filter: none; }
.exam-vip-visual { display: flex; align-items: flex-end; justify-content: flex-end; min-width: 0; padding: 34px 12px 9px 0; }
.exam-vip-visual img { display: block; width: min(205px, 125%); max-width: none; height: auto; filter: drop-shadow(0 14px 20px rgba(3, 9, 45, .32)); transform: translateX(2px); }
.exam-vip-ribbon {
  position: absolute; z-index: 4; top: 18px; right: -35px; display: grid; place-items: center;
  width: 142px; height: 35px; transform: rotate(45deg); background: linear-gradient(135deg, #ffe17a, #f4b52e);
  color: #142155; font-family: var(--font-num); font-size: 15px; font-weight: 900; letter-spacing: .06em;
  box-shadow: 0 5px 14px rgba(7, 14, 65, .24);
}

.exam-catalogue-layout { display: block; }
.exam-filter-panel {
  position: relative; z-index: 8; margin-bottom: 20px;
  padding: 20px; background: var(--surface); border: 1px solid color-mix(in srgb, var(--primary-border) 62%, var(--border)); border-radius: 18px;
  box-shadow: 0 8px 24px rgba(38, 64, 112, .06);
}
.exam-filter-head { display: flex; align-items: center; justify-content: space-between; gap: 10px 18px; grid-column: 1 / -1; }
.exam-filter-kicker { display: inline-flex; align-items: center; gap: 6px; color: var(--primary); font-size: 12px; font-weight: 700; }
.exam-filter-head h2 { margin: 3px 0 0; font-size: 17px; line-height: 1.4; }
.exam-filter-close { display: none; width: 38px; height: 38px; padding: 0; place-items: center; border: 0; border-radius: 10px; background: var(--surface-muted); color: var(--text); cursor: pointer; }
.exam-filter-form { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 14px 18px; }
.exam-filter-form .form-group { margin: 0; }
.exam-filter-form label, .exam-filter-group legend { font-size: 13px; font-weight: 700; color: var(--text); }
.exam-filter-form .form-control, .exam-filter-form .form-select { height: 46px; border-radius: 11px; }
.exam-filter-form label { display: block; margin-bottom: 6px; }
.exam-search-field, .exam-mobile-search { position: relative; }
.exam-search-field .form-control, .exam-mobile-search .form-control { padding-left: 38px; }
.exam-search-icon { position: absolute; left: 12px; bottom: 12px; z-index: 1; color: var(--text-subtle); pointer-events: none; }
/* In the heading row the field carries no visible label, so the icon centres on
   the control itself rather than sitting a label's height from the bottom. */
.exam-filter-head .exam-search-field { flex: 0 1 320px; margin-left: auto; min-width: 0; }
.exam-filter-head .exam-search-icon { top: 50%; bottom: auto; transform: translateY(-50%); }
.exam-mobile-search .exam-search-icon { bottom: 12px; }
.exam-filter-group { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); grid-column: 1 / -1; gap: 14px; min-width: 0; margin: 0; padding: 0; border: 0; }
.exam-filter-group.has-major { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.exam-filter-major-row { display: none; grid-column: 1 / -1; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.exam-filter-major-row.is-visible { display: grid; }
.exam-filter-major-row .form-group { margin: 0; }
.exam-filter-group legend { width: 100%; margin-bottom: 8px; }
.exam-filter-option { display: flex; align-items: center; gap: 9px; min-height: 38px; padding: 6px 8px; border-radius: 9px; cursor: pointer; font-weight: 500 !important; transition: background var(--t-fast), color var(--t-fast); }
.exam-filter-option:hover { background: var(--surface-hover); }
.exam-filter-option:has(input:checked) { background: var(--primary-soft); color: var(--primary-dark); font-weight: 700 !important; }
.exam-filter-option input { width: 16px; height: 16px; margin: 0; accent-color: var(--primary); flex: 0 0 auto; }
.exam-filter-option span { min-width: 0; flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.exam-filter-option small { color: var(--text-subtle); font-size: 11.5px; font-weight: 500; }
.exam-category-options { max-height: 255px; overflow-y: auto; padding-right: 3px; scrollbar-width: thin; }
.exam-difficulty-options { display: grid; grid-template-columns: 1fr 1fr; gap: 5px 6px; }
.exam-difficulty-options legend { grid-column: 1 / -1; }
.exam-difficulty-options .exam-filter-option:has(input[value="easy"]:checked) { background: var(--success-soft); color: var(--success); }
.exam-difficulty-options .exam-filter-option:has(input[value="medium"]:checked) { background: var(--warning-soft); color: var(--warning); }
.exam-difficulty-options .exam-filter-option:has(input[value="hard"]:checked) { background: var(--danger-soft); color: var(--danger); }
.exam-filter-actions { display: flex; align-items: end; justify-content: flex-end; gap: 8px; }
.exam-filter-actions .btn { min-height: 46px; white-space: nowrap; }
/* Major subjects sit four cascading dropdowns deep, so the filter offers them
   as a row of one-click chips. */
.exam-major-shortcuts {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px 12px;
  min-width: 0;
  margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border);
}
.exam-major-shortcuts-label {
  display: inline-flex; align-items: center; gap: 5px;
  color: var(--text-muted); font-size: 12.5px; font-weight: 600; white-space: nowrap;
}
.exam-major-chips { display: flex; flex-wrap: wrap; gap: 8px; min-width: 0; }
.exam-major-chip {
  display: inline-flex; align-items: center; padding: 6px 14px;
  border: 1px solid var(--border-strong); border-radius: var(--radius-pill);
  background: var(--surface); color: var(--text);
  font-size: 13px; font-weight: 600; white-space: nowrap;
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}
.exam-major-chip:hover {
  background: var(--surface-hover); color: var(--primary-dark);
  border-color: var(--primary); text-decoration: none;
}
.exam-major-chip.is-active {
  background: var(--primary-soft); border-color: var(--primary); color: var(--primary-dark);
}
/* A subject with no published set yet still gets a chip, just a quieter one. */
.exam-major-chip.is-empty:not(.is-active) { color: var(--text-muted); border-style: dashed; }
.exam-filter-mobile-apply { display: none; }

.exam-results { min-width: 0; }
.exam-results.is-filtering { opacity: .58; pointer-events: none; transition: opacity 120ms ease; }
.exam-result-toolbar {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  min-height: 52px; padding: 9px 11px 9px 14px; margin-bottom: 14px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 13px;
}
.exam-result-copy { display: flex; align-items: baseline; flex-wrap: wrap; gap: 5px 10px; }
.exam-result-copy strong { font-size: 17px; }
.exam-result-copy > span { font-size: 12px; color: var(--text-muted); }
.exam-sort-form { display: flex; align-items: center; gap: 8px; }
.exam-sort-form label { color: var(--text-muted); font-size: 12px; white-space: nowrap; }
.exam-sort-form .form-select { width: 154px; }
.exam-active-filters { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin: -5px 0 15px; }
.exam-active-filters a {
  display: inline-flex; align-items: center; gap: 7px; max-width: 260px; min-height: 32px; padding: 5px 11px;
  border: 1px solid var(--primary-border); border-radius: var(--radius-pill); background: var(--primary-soft);
  color: var(--primary-dark); font-size: 12.5px; font-weight: 600;
}
.exam-active-filters a span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.exam-active-filters a:hover { text-decoration: none; border-color: var(--primary); }
.exam-active-filters .clear { border-color: transparent; background: transparent; color: var(--text-muted); }

.exam-catalogue-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: 18px; row-gap: 20px; }
.exam-catalogue-card { display: flex; min-width: 0; min-height: 238px; padding: 17px 18px 18px; flex-direction: column; gap: 9px; border-color: color-mix(in srgb, var(--border) 82%, #b9c9e5); border-radius: 16px; box-shadow: 0 5px 15px rgba(29, 55, 105, .045); transition: transform var(--t-fast), border-color var(--t-fast), box-shadow var(--t-fast); }
.exam-catalogue-card:hover { border-color: var(--primary-border); box-shadow: 0 11px 25px rgba(35, 68, 132, .11); transform: translateY(-2px); }
.exam-card-badges { display: flex; align-items: center; gap: 5px; min-width: 0; }
.exam-card-badges .badge:first-child { max-width: 44%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.exam-card-badges .badge { min-height: 25px; padding: 3px 8px; font-size: 11px; }
.exam-difficulty { display: inline-flex; align-items: center; min-height: 25px; margin-left: auto; padding: 3px 8px; border-radius: var(--radius-pill); font-size: 11px; font-weight: 700; white-space: nowrap; }
.exam-difficulty-easy { background: var(--success-soft); color: var(--success); }
.exam-difficulty-medium, .exam-difficulty-mixed { background: var(--warning-soft); color: var(--warning); }
.exam-difficulty-hard { background: var(--danger-soft); color: var(--danger); }
/* The heading is the เรื่อง alone, so it can be bigger and still fit two lines:
   the สนาม/ภาค/วิชา that used to be in front of it are chips above, and the
   ชุดที่ that used to be behind it is a chip too — neither can be clipped. */
.exam-catalogue-card h2 { min-height: 50px; margin: 0; font-size: 17.5px; font-weight: 700; line-height: 1.42; letter-spacing: -.005em; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.exam-catalogue-card h2 a { color: var(--text); }
.exam-catalogue-card h2 a:hover { color: var(--primary); text-decoration: none; }
/* Where the set sits: one quiet line of plain text above the name.
   No frame, no fill, no radius — nothing that could be mistaken for something
   to press. It is the card's footnote, and it reads as one. Two lines at most,
   so a long วิชา wraps once and then clips rather than pushing the name down. */
.exam-card-path {
  margin: 0 0 3px;
  color: var(--text-subtle);
  font-size: 12px; font-weight: 500; line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.exam-card-description { min-height: 0; margin: 0; color: var(--text-muted); font-size: 12.5px; line-height: 1.55; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.exam-card-facts { display: flex; flex-wrap: wrap; gap: 6px 12px; margin-top: auto; color: var(--text-muted); font-size: 12px; }
.exam-card-facts span { display: inline-flex; align-items: center; gap: 4px; }
.exam-card-cta { width: 100%; min-height: 43px; margin-top: 3px; border-radius: 11px; font-size: 14px; font-weight: 700; }
.exam-card-cta .icon { transition: transform var(--t-fast); }
.exam-card-cta:hover .icon { transform: translateX(3px); }
.exam-empty-state { display: grid; justify-items: center; gap: 7px; min-height: 320px; padding: 60px 20px; text-align: center; border: 1px dashed var(--border-strong); border-radius: var(--radius-lg); background: var(--surface); }
.exam-empty-state > span { display: grid; place-items: center; width: 56px; height: 56px; border-radius: 16px; background: var(--primary-soft); color: var(--primary); }
.exam-empty-state h2 { margin: 5px 0 0; font-size: 18px; }
.exam-empty-state p { margin: 0 0 7px; color: var(--text-muted); font-size: 13px; }
.exam-mobile-tools { display: none; }
.exam-filter-backdrop { display: none; }
.exam-catalogue .pagination { margin-top: 16px; }

@media (max-width: 1120px) and (min-width: 1025px) {
  .exam-catalogue-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 1180px) {
  .exam-catalogue-head { grid-template-columns: 1fr; min-height: 0; padding: 24px 30px 28px; }
  /* Narrow enough that the illustration's blank left side no longer fits the
     copy, so the VIP card drops back to the plain gradient. */
  .exam-catalogue-head.is-vip-user {
    aspect-ratio: auto;
    padding-right: 30px;
    background:
      radial-gradient(circle at 52% 16%, rgba(123, 97, 255, .09), transparent 27%),
      radial-gradient(circle at 84% 92%, rgba(37, 99, 235, .09), transparent 31%),
      linear-gradient(135deg, var(--surface), color-mix(in srgb, var(--primary-soft) 42%, var(--surface)));
  }
  .exam-catalogue-intro h1 { font-size: 46px; }
  .exam-catalogue-intro > p { max-width: 720px; }
  .exam-vip-compact { min-height: 218px; grid-template-columns: minmax(0, 1.35fr) minmax(190px, .65fr); }
  .exam-vip-visual img { width: min(220px, 118%); }
}

@media (max-width: 1024px) {
  .exam-catalogue-head { gap: 20px; }
  .exam-mobile-tools { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; margin-bottom: 12px; }
  .exam-mobile-search .form-control { height: 42px; }
  .exam-filter-trigger { min-height: 42px; }
  .exam-catalogue-layout { display: block; }
  .exam-catalogue-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .exam-filter-enhanced .exam-filter-panel {
    position: fixed; inset: auto 0 0; z-index: 230; width: 100%; max-height: min(88vh, 720px); margin: 0;
    overflow-y: auto; padding: 20px 18px max(18px, env(safe-area-inset-bottom)); border: 0; border-radius: 22px 22px 0 0;
    transform: translateY(105%); transition: transform var(--t); box-shadow: 0 -18px 45px rgba(8, 22, 52, .2);
  }
  .exam-filter-enhanced .exam-filter-panel.is-open { transform: none; }
  .exam-filter-enhanced .exam-filter-close { display: grid; }
  .exam-filter-form { display: grid; grid-template-columns: 1fr; gap: 16px; }
  .exam-filter-form .exam-search-field { display: none; }
  .exam-filter-group { grid-template-columns: 1fr; gap: 13px; }
  .exam-filter-group.has-major { grid-template-columns: 1fr; }
  .exam-filter-major-row { grid-template-columns: 1fr; }
  .exam-filter-actions {
    position: sticky; bottom: calc(-1 * max(18px, env(safe-area-inset-bottom))); z-index: 2;
    display: grid; grid-template-columns: minmax(0, .75fr) minmax(0, 1.25fr); padding: 12px 0 max(18px, env(safe-area-inset-bottom));
    background: linear-gradient(to bottom, color-mix(in srgb, var(--surface) 72%, transparent), var(--surface) 24%);
  }
  .exam-filter-actions .btn { width: 100%; }
  /* The chips scroll sideways in the mobile filter sheet rather than stacking
     into a tall block above the sticky action row. */
  .exam-major-shortcuts { gap: 6px; }
  .exam-major-chips {
    flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none;
    max-width: 100%;
    margin-inline: -2px; padding: 2px;
  }
  .exam-major-chips::-webkit-scrollbar { display: none; }
  .exam-filter-mobile-apply { display: inline-flex; }
  .exam-filter-enhanced .exam-filter-backdrop {
    position: fixed; inset: 0; z-index: 225; width: 100%; height: 100%; padding: 0;
    border: 0; background: rgba(8, 20, 45, .48); cursor: pointer;
  }
  .exam-filter-enhanced .exam-filter-backdrop:not([hidden]) { display: block; }
  body.exam-filter-open { overflow: hidden; }
}

@media (max-width: 640px) {
  .exam-catalogue { padding-top: 8px; }
  .exam-catalogue-head { gap: 14px; padding: 18px 16px; margin-bottom: 18px; border-radius: 20px; }
  .exam-catalogue-intro .eyebrow { min-height: 39px; padding-inline: 15px; margin-bottom: 15px; font-size: 13px; }
  .exam-catalogue-intro h1 { font-size: clamp(38px, 11vw, 44px); }
  .exam-catalogue-intro > p { margin-top: 15px; font-size: 14px; line-height: 1.62; }
  .exam-catalogue-summary { width: 100%; min-height: 76px; margin-top: 16px; padding: 8px 4px; }
  .exam-stat { gap: 9px; padding: 0 10px; }
  .exam-stat-icon { width: 42px; height: 42px; border-radius: 13px; }
  .exam-stat-icon .icon { width: 20px; height: 20px; }
  .exam-stat b { font-size: 24px; }
  .exam-stat small { margin-top: 5px; font-size: 12px; }
  .exam-vip-compact { grid-template-columns: 1fr; min-height: 305px; }
  .exam-vip-content { padding: 20px 18px 66px; }
  .exam-vip-compact h2 { font-size: 22px; }
  .exam-vip-compact p { font-size: 11.5px; }
  .exam-vip-cta { width: 100%; min-width: 0; }
  .exam-vip-visual { position: absolute; right: 8px; bottom: 2px; z-index: 1; justify-content: flex-end; padding: 0; margin: 0; }
  .exam-vip-visual img { width: min(132px, 39vw); max-width: 100%; opacity: .78; }
  .exam-vip-ribbon { top: 15px; right: -38px; }
  .exam-mobile-tools { grid-template-columns: 1fr; }
  .exam-filter-trigger { width: 100%; }
  .exam-result-toolbar { align-items: flex-start; }
  .exam-result-copy { padding-top: 3px; }
  .exam-sort-form { align-items: flex-start; flex-direction: column; gap: 2px; }
  .exam-sort-form .form-select { width: 132px; }
  .exam-catalogue-grid { grid-template-columns: 1fr; gap: 10px; }
  .exam-catalogue-card { min-height: 210px; }
}

@media print {
  .exam-filter-panel, .exam-mobile-tools, .exam-vip-compact, .exam-result-toolbar, .exam-active-filters, .exam-catalogue .pagination { display: none !important; }
  .exam-catalogue-layout, .exam-catalogue-grid { display: block; }
  .exam-catalogue-card { break-inside: avoid; margin-bottom: 10px; }
}

/* ========================================================== RANKING REDESIGN
   Modernized leaderboard layout matching Target Design (Image 1) with
   prominent 3D podium (Ranks 1/2/3), empty-state experience with 3D trophy
   illustration, compact filter card, pill segmented tabs, and update info bar.
   -------------------------------------------------------------------------- */

.ranking-page-shell {
  position: relative;
  min-height: 80vh;
  padding-bottom: 30px;
}

/* Background subtle ambient decorations */
.ranking-bg-glow {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 620px;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(circle at 12% 16%, rgba(219, 234, 254, 0.42) 0%, transparent 45%),
    radial-gradient(circle at 88% 18%, rgba(224, 231, 255, 0.38) 0%, transparent 42%);
}

.ranking-bg-dots-left,
.ranking-bg-dots-right {
  position: absolute;
  width: 48px;
  height: 84px;
  pointer-events: none;
  z-index: 0;
  opacity: 0.55;
  background-image: radial-gradient(#94a3b8 1.75px, transparent 1.75px);
  background-size: 16px 16px;
}

.ranking-bg-dots-left {
  top: 470px;
  left: max(16px, calc(50% - 530px));
}

.ranking-bg-dots-right {
  top: 410px;
  right: max(16px, calc(50% - 530px));
}

.container-ranking {
  position: relative;
  z-index: 1;
  max-width: 960px;
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Header & Typography */
.ranking-hero {
  padding: 24px 0 18px;
  text-align: center;
}

.ranking-eyebrow-wrap {
  display: flex;
  justify-content: center;
  margin-bottom: 12px;
}

.ranking-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 14px;
  border-radius: var(--radius-pill);
  background: #eff6ff;
  border: 1px solid #dbeafe;
  color: #2563eb;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.2;
}

.ranking-hero-title {
  font-size: clamp(34px, 3.8vw, 46px);
  font-weight: 800;
  color: #0f172a;
  line-height: 1.15;
  margin: 0 0 10px;
  letter-spacing: -0.025em;
}

.ranking-hero-desc {
  font-size: clamp(14.5px, 1.2vw, 16px);
  color: #64748b;
  margin: 0 auto 22px;
  max-width: 62ch;
  line-height: 1.6;
}

/* Period Filter Segmented Control */
.ranking-tabs-wrap {
  display: flex;
  justify-content: center;
  margin-bottom: 22px;
}

.ranking-segmented-tabs {
  display: inline-flex;
  align-items: center;
  background: #ffffff;
  border: 1px solid #e2e8f0;
  border-radius: var(--radius-pill);
  padding: 4px;
  gap: 4px;
  box-shadow: 0 2px 8px rgba(15, 23, 42, 0.04);
}

.ranking-tab {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 42px;
  padding: 0 20px;
  border-radius: var(--radius-pill);
  font-size: 14.5px;
  font-weight: 600;
  color: #475569;
  text-decoration: none;
  background: transparent;
  transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
  white-space: nowrap;
}

.ranking-tab:hover {
  color: #0f172a;
  background: #f8fafc;
  text-decoration: none;
}

.ranking-tab.active {
  background: #2563eb;
  color: #ffffff;
  box-shadow: 0 4px 12px rgba(37, 99, 235, 0.28);
}

.ranking-tab.active:hover {
  color: #ffffff;
}

.ranking-tab .icon {
  flex-shrink: 0;
}

/* Compact Filter / Exam Selector Card */
.ranking-filter-card {
  background: #ffffff;
  border: 1px solid #e2e8f0;
  border-radius: 16px;
  padding: 14px 18px;
  margin-bottom: 22px;
  box-shadow: 0 2px 8px rgba(15, 23, 42, 0.03);
}

.ranking-filter-form {
  display: flex;
  align-items: flex-end;
  gap: 14px;
  width: 100%;
}

.ranking-filter-field {
  flex: 1 1 auto;
  min-width: 0;
}

.ranking-filter-label {
  display: block;
  font-size: 13px;
  font-weight: 700;
  color: #1e293b;
  margin-bottom: 6px;
}

.ranking-select-wrap {
  position: relative;
  width: 100%;
}

.ranking-select {
  width: 100%;
  height: 44px;
  border: 1px solid #cbd5e1;
  border-radius: 10px;
  padding: 0 14px;
  font-size: 14px;
  color: #334155;
  background-color: #ffffff;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.ranking-select:focus {
  border-color: #2563eb;
  outline: none;
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12);
}

.ranking-filter-btn {
  flex: 0 0 auto;
  height: 44px;
  padding: 0 20px;
  border: 1px solid #cbd5e1;
  border-radius: 10px;
  background: #ffffff;
  color: #1e293b;
  font-size: 14px;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  transition: all 0.15s ease;
}

.ranking-filter-btn:hover {
  background: #f8fafc;
  border-color: #94a3b8;
  color: #0f172a;
}

/* Main Ranking Card */
.ranking-main-card {
  position: relative;
  background: #ffffff;
  border: 1px solid #e2e8f0;
  border-radius: 22px;
  padding: 38px 30px 22px;
  box-shadow: 0 12px 36px rgba(15, 23, 42, 0.04);
  overflow: hidden;
  margin-bottom: 28px;
  background-image: radial-gradient(circle at 50% 10%, rgba(239, 246, 255, 0.65) 0%, transparent 62%);
}

/* Top 3 Podium Grid */
.ranking-podium-grid {
  display: grid;
  grid-template-columns: 1fr 1.1fr 1fr;
  align-items: end;
  gap: 20px;
  margin: 14px 0 28px;
}

.podium-column {
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
  min-width: 0;
}

.podium-column-1 {
  order: 2;
  z-index: 3;
}

.podium-column-2 {
  order: 1;
  z-index: 2;
}

.podium-column-3 {
  order: 3;
  z-index: 2;
}

.podium-medal-badge {
  position: relative;
  z-index: 4;
  margin-bottom: -22px;
  display: flex;
  justify-content: center;
  transition: transform 0.25s ease;
}

.podium-column:hover .podium-medal-badge {
  transform: translateY(-2px) scale(1.03);
}

.podium-user-card {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: 270px;
  background: #ffffff;
  border-radius: 18px;
  padding: 34px 14px 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  box-sizing: border-box;
}

.podium-column-1 .podium-user-card {
  max-width: 290px;
  min-height: 232px;
  border: 1.5px solid #fde047;
  box-shadow: 0 10px 28px rgba(245, 158, 11, 0.13);
  background: linear-gradient(180deg, #ffffff 0%, #fffdf6 100%);
}

.podium-column-2 .podium-user-card {
  min-height: 204px;
  border: 1px solid #e2e8f0;
  box-shadow: 0 6px 20px rgba(148, 163, 184, 0.12);
  background: linear-gradient(180deg, #ffffff 0%, #fafcff 100%);
}

.podium-column-3 .podium-user-card {
  min-height: 204px;
  border: 1px solid #fed7aa;
  box-shadow: 0 6px 20px rgba(234, 88, 12, 0.09);
  background: linear-gradient(180deg, #ffffff 0%, #fffbf8 100%);
}

/* Avatar in Podium */
.podium-avatar-wrap {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  margin-bottom: 10px;
  position: relative;
}

.podium-column-1 .podium-avatar-wrap {
  width: 62px;
  height: 62px;
}

.podium-avatar-empty {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: #f1f5f9;
  color: #94a3b8;
  display: grid;
  place-items: center;
  border: 2px solid #ffffff;
  box-shadow: 0 2px 8px rgba(15, 23, 42, 0.06);
}

.podium-avatar-wrap img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid #ffffff;
  box-shadow: 0 2px 8px rgba(15, 23, 42, 0.08);
}

.podium-name {
  font-size: 16.5px;
  font-weight: 700;
  color: #0f172a;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  line-height: 1.3;
}

.podium-column-1 .podium-name {
  font-size: 17.5px;
}

.podium-sub {
  font-size: 13px;
  color: #64748b;
  margin-top: 3px;
  line-height: 1.3;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  flex-wrap: wrap;
}

.podium-score-pill {
  margin-top: 10px;
  padding: 4px 14px;
  border-radius: var(--radius-pill);
  font-size: 13px;
  font-weight: 700;
  font-family: var(--font-num, inherit);
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.podium-score-pill.gold {
  background: #fef3c7;
  color: #b45309;
  border: 1px solid #fde68a;
}

.podium-score-pill.silver {
  background: #eff6ff;
  color: #1d4ed8;
  border: 1px solid #dbeafe;
}

.podium-score-pill.bronze {
  background: #ffedd5;
  color: #c2410c;
  border: 1px solid #fed7aa;
}

/* 3D Podium Pedestal Base */
.podium-base-pedestal {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 270px;
  margin-top: -6px;
  display: flex;
  justify-content: center;
}

.podium-column-1 .podium-base-pedestal {
  max-width: 290px;
}

.podium-pedestal-svg {
  width: 100%;
  display: block;
  filter: drop-shadow(0 4px 8px rgba(15, 23, 42, 0.08));
}

/* Empty State Experience Inside Card */
.ranking-empty-experience {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 34px;
  padding: 24px 20px 24px;
  position: relative;
  z-index: 2;
}

.ranking-empty-illu {
  flex: 0 0 160px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.ranking-trophy-illu-svg {
  max-width: 100%;
  height: auto;
  filter: drop-shadow(0 6px 14px rgba(37, 99, 235, 0.08));
}

.ranking-empty-content {
  flex: 1 1 auto;
  max-width: 500px;
}

.ranking-empty-headline {
  font-size: 21px;
  font-weight: 800;
  color: #0f172a;
  margin: 0 0 8px;
  line-height: 1.25;
}

.ranking-empty-desc {
  font-size: 14.5px;
  color: #64748b;
  line-height: 1.55;
  margin: 0 0 18px;
}

.ranking-empty-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.btn-ranking-primary {
  height: 48px;
  padding: 0 24px;
  border-radius: 11px;
  background: #2563eb;
  color: #ffffff;
  font-weight: 700;
  font-size: 15px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  border: none;
  box-shadow: 0 4px 14px rgba(37, 99, 235, 0.28);
  transition: all 0.2s ease;
}

.btn-ranking-primary:hover {
  background: #1d4ed8;
  transform: translateY(-1px);
  box-shadow: 0 6px 18px rgba(37, 99, 235, 0.35);
  color: #ffffff;
  text-decoration: none;
}

.btn-ranking-secondary {
  height: 48px;
  padding: 0 22px;
  border-radius: 11px;
  background: #ffffff;
  color: #1e293b;
  border: 1px solid #cbd5e1;
  font-weight: 600;
  font-size: 15px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  transition: all 0.2s ease;
}

.btn-ranking-secondary:hover {
  background: #f8fafc;
  border-color: #94a3b8;
  color: #0f172a;
  transform: translateY(-1px);
  text-decoration: none;
}

/* Update Info Bar */
.ranking-info-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 11px 18px;
  border-radius: 10px;
  background: #eff6ff;
  color: #2563eb;
  font-size: 13.5px;
  font-weight: 500;
  margin-top: 18px;
  text-align: center;
}

.ranking-info-icon {
  flex-shrink: 0;
  display: inline-flex;
  color: #2563eb;
}

.ranking-info-text {
  line-height: 1.45;
}

/* Populated State: Following Ranks (4+) Section */
.ranking-following-wrap {
  margin-top: 24px;
  margin-bottom: 16px;
}

.ranking-following-wrap .rank-row {
  background: #ffffff;
  border: 1px solid #e2e8f0;
  border-radius: 12px;
  padding: 12px 18px;
}

.ranking-following-wrap .rank-row:hover {
  background: #f8fafc;
}

/* Responsive adjustments */
@media (max-width: 860px) {
  .ranking-podium-grid {
    gap: 12px;
  }
  .podium-user-card {
    padding: 28px 10px 16px;
  }
  .podium-name {
    font-size: 15px;
  }
  .ranking-empty-experience {
    gap: 20px;
  }
}

@media (max-width: 640px) {
  .ranking-hero-title {
    font-size: 32px;
  }
  .ranking-segmented-tabs {
    flex-wrap: wrap;
    justify-content: center;
  }
  .ranking-tab {
    padding: 0 14px;
    height: 38px;
    font-size: 13.5px;
  }
  .ranking-filter-form {
    flex-direction: column;
    align-items: stretch;
  }
  .ranking-filter-btn {
    justify-content: center;
    width: 100%;
  }
  .ranking-main-card {
    padding: 26px 16px 18px;
  }
  .ranking-podium-grid {
    grid-template-columns: 1fr 1fr;
    gap: 14px 10px;
  }
  .podium-column-1 {
    grid-column: 1 / -1;
    order: 1;
    margin-bottom: 10px;
  }
  .podium-column-2 {
    order: 2;
  }
  .podium-column-3 {
    order: 3;
  }
  .podium-column-1 .podium-user-card {
    max-width: 100%;
  }
  .podium-column-2 .podium-user-card,
  .podium-column-3 .podium-user-card {
    max-width: 100%;
  }
  .ranking-empty-experience {
    flex-direction: column;
    text-align: center;
    padding: 16px 8px 20px;
  }
  .ranking-empty-actions {
    justify-content: center;
    width: 100%;
  }
  .btn-ranking-primary,
  .btn-ranking-secondary {
    width: 100%;
    justify-content: center;
  }
  .ranking-bg-dots-left,
  .ranking-bg-dots-right {
    display: none;
  }
}

/* ============================================================================
   ABOUT US — BRAND / PRODUCT PAGE
   Four sections: hero, approach, proof, call to action. Every rule below is
   scoped to a class this one page owns, so nothing here reaches the shared
   header, footer or any other screen.
   ============================================================================ */

.container-brand {
  max-width: 1120px;
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--space-md);
  padding-right: var(--space-md);
  width: 100%;
}

/* --------------------------------------------------- 1. About introduction */
/* A reading section, not a hero: one flat surface, one border, no decorative
   layer competing with the prose. The two columns divide role rather than
   text — the heading block on the left, the reading column on the right — so
   no paragraph is ever set to half the page width. */
.about-hero {
  display: grid;
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: 34px 48px;
  align-items: start;
  padding: 34px 36px 36px;
  margin-top: var(--space);
  margin-bottom: 48px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
}

.about-hero-content { min-width: 0; }

.about-hero-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 13px;
  background: var(--primary-soft);
  border: 1px solid var(--primary-border);
  color: var(--primary);
  border-radius: var(--radius-pill);
  font-size: 12.5px;
  font-weight: 600;
  margin-bottom: 14px;
}

.about-hero-title {
  font-size: clamp(27px, 2.9vw, 36px);
  font-weight: 800;
  line-height: 1.22;
  color: var(--navy);
  margin: 0 0 14px;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

/* The one-sentence answer to "what is this", set a step above body copy so it
   reads as the summary of everything to its right. */
.about-hero-lead {
  margin: 0;
  padding-top: 14px;
  color: var(--text);
  font-size: 15.5px;
  font-weight: 500;
  line-height: 1.8;
  border-top: 2px solid var(--primary-soft-2);
  /* Thai does not hyphenate, so a paragraph left to itself strands single
     words on their own line. */
  text-wrap: pretty;
}

.about-hero-body {
  min-width: 0;
  /* The measure, not the column: the grid track can be wider than this and
     the lines still stay comfortable to read. */
  max-width: 66ch;
}

.about-hero-block + .about-hero-block {
  margin-top: 22px;
  padding-top: 22px;
  border-top: 1px solid var(--border);
}

.about-hero-block h2 {
  margin: 0 0 9px;
  color: var(--navy);
  font-size: 17.5px;
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: -0.01em;
}

.about-hero-block p {
  margin: 0 0 11px;
  color: var(--text-muted);
  font-size: 14.5px;
  line-height: 1.82;
  text-wrap: pretty;
}
.about-hero-block p:last-child { margin-bottom: 0; }

/* -------------------------------------------------------- Section framework */
.about-section {
  margin-bottom: 48px;
}

.about-header-center {
  text-align: center;
  max-width: 660px;
  margin: 0 auto 26px;
}

.about-section-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--primary);
  letter-spacing: 0.03em;
  margin-bottom: 8px;
}

.about-section-title {
  font-size: clamp(21px, 2.6vw, 28px);
  font-weight: 800;
  color: var(--navy);
  line-height: 1.3;
  margin: 0 0 8px;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

.about-section-subtitle {
  font-size: 14.5px;
  line-height: 1.65;
  color: var(--text-muted);
  margin: 0;
  text-wrap: pretty;
}

/* ------------------------------------------------- 2. Approach: four cards */
.about-values-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}

.about-value-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 18px 17px;
  display: flex;
  flex-direction: column;
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
  box-shadow: var(--shadow-xs);
}

.about-value-card:hover {
  box-shadow: 0 6px 16px -6px rgba(28, 71, 204, 0.12);
  border-color: var(--primary-border);
}

.about-value-icon {
  width: 40px;
  height: 40px;
  border-radius: 11px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 12px;
}

.about-value-card:nth-child(1) .about-value-icon { background: #eff6ff; color: #1c47cc; }
.about-value-card:nth-child(2) .about-value-icon { background: #fffbeb; color: #d97706; }
.about-value-card:nth-child(3) .about-value-icon { background: #ecfdf5; color: #059669; }
.about-value-card:nth-child(4) .about-value-icon { background: #f5f3ff; color: #7c3aed; }

.about-value-title {
  font-size: 15.5px;
  font-weight: 700;
  color: var(--navy);
  margin: 0 0 5px;
  line-height: 1.35;
}

.about-value-desc {
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--text-muted);
  margin: 0;
}

/* ---------------------------- 3. Proof: live counts and the fields covered */
.about-proof {
  padding: 26px 26px 22px;
  background: linear-gradient(180deg, #f9fbfe 0%, #f1f5fb 100%);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
}

.about-stats-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.about-stat-item {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 14px;
  text-align: center;
  box-shadow: var(--shadow-xs);
}

.about-stat-icon-wrap {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  background: var(--primary-soft);
  color: var(--primary);
  margin-bottom: 7px;
}

.about-stat-num {
  font-size: clamp(24px, 2.6vw, 31px);
  font-weight: 800;
  color: var(--navy);
  line-height: 1.1;
  letter-spacing: -0.02em;
  font-feature-settings: 'tnum' 1;
  margin-bottom: 2px;
}

.about-stat-label {
  font-size: 13.5px;
  font-weight: 700;
  color: var(--text);
  margin: 0;
}

/* A list, not four more cards: the name is the only thing to read and the
   action is the same on every row, so rows scan faster than a grid. */
.about-exam-list {
  list-style: none;
  margin: 16px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.about-exam-row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  text-decoration: none;
  color: inherit;
  transition: border-color var(--t-fast), background var(--t-fast);
}

.about-exam-row:hover {
  background: #fdfeff;
  border-color: var(--primary-border);
  text-decoration: none;
}

.about-exam-mark {
  display: inline-flex;
  flex: 0 0 34px;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 9px;
  background: var(--primary-soft);
  color: var(--primary);
}

.about-exam-name { min-width: 0; overflow: hidden; }
.about-exam-name strong,
.about-exam-name small { display: block; }
.about-exam-name strong {
  font-size: 15px;
  font-weight: 700;
  color: var(--navy);
  line-height: 1.35;
}
/* One line, whatever the agency is called: a wrapped second line would make
   the rows different heights and push the action out of alignment. */
.about-exam-name small {
  margin-top: 1px;
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.about-exam-go {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 5px;
  margin-left: auto;
  font-size: 13px;
  font-weight: 600;
  color: var(--primary);
  white-space: nowrap;
}
.about-exam-go .icon { transition: transform var(--t-fast); }
.about-exam-row:hover .about-exam-go .icon { transform: translateX(3px); }

/* ------------------------------------------------ 4. Developer and contact */
.about-contact-text {
  margin: 0 0 10px;
  color: var(--text-muted);
  font-size: 14.5px;
  line-height: 1.72;
  max-width: 54ch;
  text-wrap: pretty;
}
.about-contact-text:last-of-type { margin-bottom: 18px; }

/* The QR plate. A code needs a quiet zone and a white ground to scan, so the
   plate is white in both themes and the image is never cropped or scaled
   below a readable size. */
.about-contact-qr {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  min-width: 0;
  margin: 0;
}

.about-qr-plate {
  display: block;
  padding: 14px;
  background: #ffffff;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: 0 2px 10px -6px rgba(12, 23, 48, 0.12);
}

.about-qr-plate img {
  display: block;
  width: 200px;
  height: 200px;
  max-width: 100%;
  /* The source is a square code: contain, never cover, or a corner marker is
     cut off and the code stops scanning. */
  object-fit: contain;
  border-radius: 4px;
}

.about-contact-qr figcaption {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--text-muted);
  font-size: 13px;
  font-weight: 600;
}
.about-contact-qr figcaption .icon { color: #06c755; }

.about-contact-mail:focus-visible,
.about-exam-row:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 3px;
}

/* --------------------------------------------------------------- Responsive */
@media (max-width: 992px) {
  /* One column below the desktop split: two narrow prose columns read worse
     than one wide one, and the heading no longer has room to sit beside it. */
  .about-hero {
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
    padding: 28px 26px 30px;
    margin-bottom: 40px;
  }
  .about-hero-lead { max-width: 66ch; }
  .about-section { margin-bottom: 40px; }
  .about-values-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .about-stats-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
  /* Two columns leave the agency line wrapping and the action squeezed at this
     width, so the rows go full width and stay one line each. minmax(0, …)
     rather than 1fr: a plain 1fr track cannot shrink below the row's
     min-content width, which pushes the action past the container edge. */
  .about-exam-list { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 640px) {
  .container-brand {
    padding-left: var(--space);
    padding-right: var(--space);
  }
  .about-hero {
    padding: 22px 17px 24px;
    gap: 20px;
    border-radius: var(--radius-lg);
    margin-bottom: 32px;
  }
  .about-hero-title { font-size: 25px; line-height: 1.24; margin-bottom: 12px; }
  .about-hero-lead { padding-top: 12px; font-size: 14.5px; line-height: 1.75; }
  .about-hero-block + .about-hero-block { margin-top: 18px; padding-top: 18px; }
  .about-hero-block h2 { font-size: 16.5px; }
  .about-hero-block p { font-size: 14px; line-height: 1.78; }

  .about-section { margin-bottom: 32px; }
  .about-header-center { margin-bottom: 20px; }
  .about-values-grid { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .about-value-card { padding: 16px 15px; }
  .about-value-icon { width: 36px; height: 36px; margin-bottom: 10px; }

  .about-proof {
    padding: 20px 15px 18px;
    border-radius: var(--radius-lg);
  }
  .about-stats-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .about-stat-item { padding: 13px 10px; }
  .about-stat-num { font-size: 23px; }
  .about-stat-label { font-size: 12.5px; }

  .about-exam-list { grid-template-columns: minmax(0, 1fr); margin-top: 12px; }
  .about-exam-row { padding: 11px 12px; gap: 10px; }
  .about-exam-name strong { font-size: 14.5px; }
  .about-exam-go { font-size: 12.5px; }

  .about-contact-qr { align-items: center; }
}

/* ------------------------------------------------------------- Dark theme */
:root[data-theme="dark"] .about-hero,
:root[data-theme="dark"] .about-proof {
  background: var(--surface-raised);
  border-color: var(--border);
}
:root[data-theme="dark"] .about-value-card,
:root[data-theme="dark"] .about-stat-item,
:root[data-theme="dark"] .about-exam-row {
  background: var(--surface);
  border-color: var(--border);
}
:root[data-theme="dark"] .about-exam-row:hover { background: var(--surface-hover); }
:root[data-theme="dark"] .about-hero-title,
:root[data-theme="dark"] .about-section-title,
:root[data-theme="dark"] .about-value-title,
:root[data-theme="dark"] .about-stat-num,
:root[data-theme="dark"] .about-hero-block h2,
:root[data-theme="dark"] .about-contact-name,
:root[data-theme="dark"] .about-exam-name strong { color: var(--text); }
:root[data-theme="dark"] .about-hero-lead {
  color: var(--text);
  border-top-color: rgba(56, 110, 227, 0.35);
}
:root[data-theme="dark"] .about-hero-block p { color: var(--text-muted); }
:root[data-theme="dark"] .about-hero-badge {
  color: #93b4fb;
  background: rgba(56, 110, 227, 0.14);
  border-color: rgba(56, 110, 227, 0.32);
}
:root[data-theme="dark"] .about-value-card:nth-child(1) .about-value-icon,
:root[data-theme="dark"] .about-exam-mark,
:root[data-theme="dark"] .about-stat-icon-wrap {
  color: #93b4fb;
  background: rgba(56, 110, 227, 0.14);
  border-color: rgba(56, 110, 227, 0.32);
}
:root[data-theme="dark"] .about-value-card:nth-child(2) .about-value-icon { background: rgba(217, 119, 6, 0.14); color: #f0b967; }
:root[data-theme="dark"] .about-value-card:nth-child(3) .about-value-icon { background: rgba(5, 150, 105, 0.14); color: #5ecf9c; }
:root[data-theme="dark"] .about-value-card:nth-child(4) .about-value-icon { background: rgba(124, 58, 237, 0.14); color: #b394f7; }

/* ============================================================================
   ABOUT PAGE — EDITORIAL REDESIGN
   Final page-scoped layer for the reference-led About composition. Shared
   navigation and footer selectors are intentionally absent from this block.
   ============================================================================ */
.container-brand {
  max-width: 1180px;
  padding-inline: 28px;
}

.about-hero {
  position: relative;
  display: block;
  overflow: hidden;
  padding: 46px 52px 40px;
  margin: 16px 0 42px;
  border: 1px solid #dce6f4;
  border-radius: 24px;
  background: #fbfdff;
  background: linear-gradient(180deg, #ffffff 0%, #f7faff 100%);
  box-shadow: 0 8px 30px rgba(26, 55, 105, .035);
  text-align: center;
}
.about-hero-content {
  position: relative;
  z-index: 2;
  max-width: 860px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.about-hero-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  width: fit-content;
  margin: 0 auto 16px;
  padding: 6px 16px;
  border: 1px solid #d4e3fa;
  border-radius: 9999px;
  background: #edf4fe;
  color: #1e4eb8;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .02em;
}
.about-hero-title {
  margin: 0 auto 14px;
  color: var(--navy);
  font-size: clamp(27px, 3.2vw, 36px);
  font-weight: 800;
  line-height: 1.28;
  letter-spacing: -.025em;
  text-wrap: balance;
  max-width: 840px;
}
.about-hero-lead {
  margin: 0 auto 20px;
  padding: 0;
  border: 0;
  color: #2b3d5b;
  font-size: clamp(16px, 1.6vw, 17.5px);
  font-weight: 500;
  line-height: 1.8;
  max-width: 820px;
  text-wrap: pretty;
}
.about-hero-letter-body {
  max-width: 800px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
  color: #4b5c77;
  font-size: 16px;
  font-weight: 400;
  line-height: 1.88;
  text-wrap: pretty;
  text-align: center;
}
.about-hero-letter-body p {
  margin: 0;
}
.about-hero-closing {
  position: relative;
  max-width: 680px;
  width: 100%;
  margin: 22px auto 0;
  padding: 15px 28px;
  border: 1px solid #dbe6f5;
  border-radius: 14px;
  background: rgba(255, 255, 255, .85);
  box-shadow: 0 3px 12px rgba(38, 79, 142, .035);
}
.about-hero-closing p {
  margin: 0;
  color: #1e3d6d;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.72;
}
.about-hero-signature {
  margin-top: 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  text-align: center;
}
.about-hero-signature-line {
  display: block;
  width: 44px;
  height: 2px;
  background: #c5d8f3;
  border-radius: 2px;
  margin-bottom: 10px;
}
.about-hero-signature-text {
  font-size: 13.5px;
  font-weight: 700;
  color: #244b8f;
  letter-spacing: .01em;
}
.about-hero-signature-sub {
  font-size: 11.5px;
  color: #7284a1;
  font-weight: 400;
}

.about-section { margin-bottom: 40px; }
.about-header-center { max-width: 740px; margin-bottom: 20px; }
.about-section-eyebrow {
  position: relative;
  gap: 6px;
  margin-bottom: 7px;
  color: #2862dc;
  font-size: 11.5px;
  letter-spacing: .02em;
}
.about-section-eyebrow::before,
.about-section-eyebrow::after {
  content: '';
  width: 17px;
  height: 1px;
  background: #9ab7ef;
}
.about-section-title {
  margin-bottom: 7px;
  color: #0b1f3a;
  font-size: clamp(25px, 2.45vw, 31px);
  line-height: 1.22;
  letter-spacing: -.025em;
}
.about-section-subtitle { color: #72809a; font-size: 13.5px; line-height: 1.6; }

.about-values-grid { gap: 17px; align-items: stretch; }
.about-value-card {
  min-height: 175px;
  padding: 19px 18px;
  border-radius: 16px;
  box-shadow: 0 5px 16px rgba(22, 48, 91, .045);
}
.about-value-card:nth-child(1) { background: linear-gradient(145deg, #fff 58%, #f3f8ff); }
.about-value-card:nth-child(2) { background: linear-gradient(145deg, #fff 58%, #fff9ed); }
.about-value-card:nth-child(3) { background: linear-gradient(145deg, #fff 58%, #effbf6); }
.about-value-card:nth-child(4) { background: linear-gradient(145deg, #fff 58%, #f7f2ff); }
.about-value-card:hover { transform: translateY(-2px); }
.about-value-icon {
  width: 46px;
  height: 46px;
  margin-bottom: 14px;
  border-radius: 13px;
}
.about-value-title { margin-bottom: 8px; color: #0b1f3a; font-size: 18px; line-height: 1.32; }
.about-value-desc { color: #65738b; font-size: 13.5px; line-height: 1.65; }

.about-proof {
  position: relative;
  overflow: hidden;
  padding: 18px 32px 22px;
  border-color: #d9e7f8;
  border-radius: 19px;
  background: #f5f9ff;
}
.about-proof::before {
  content: '';
  position: absolute;
  left: 42px;
  bottom: 66px;
  width: 110px;
  height: 108px;
  opacity: .45;
  background: linear-gradient(to top, #dbe9ff 0 0) 0 100% / 18px 68px no-repeat,
              linear-gradient(to top, #dbe9ff 0 0) 32px 100% / 18px 108px no-repeat,
              linear-gradient(to top, #dbe9ff 0 0) 64px 100% / 18px 82px no-repeat,
              linear-gradient(to top, #dbe9ff 0 0) 96px 100% / 18px 45px no-repeat;
}
.about-proof .about-header-center { position: relative; z-index: 2; margin-bottom: 13px; }
.about-stats-grid { position: relative; z-index: 2; gap: 13px; }
.about-stat-item {
  min-height: 102px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 15px 12px;
  border-radius: 13px;
  box-shadow: 0 5px 16px rgba(22, 48, 91, .05);
}
.about-stat-icon-wrap { width: 35px; height: 35px; margin-bottom: 7px; border-radius: 9px; }
.about-stat-num { margin-bottom: 3px; color: #0b1f3a; font-size: clamp(29px, 2.7vw, 36px); }
.about-stat-label { color: #253b60; font-size: 13px; }
.about-proof-note {
  position: absolute;
  z-index: 1;
  top: 36px;
  right: 28px;
  color: #7da0e2;
  font-size: 13px;
  font-style: italic;
  font-weight: 600;
  line-height: 1.35;
  transform: rotate(7deg);
}

.about-contact-section {
  position: relative;
  overflow: hidden;
  scroll-margin-top: 92px;
  padding: 26px 28px 30px;
  margin-bottom: 28px;
  border: 1px solid #d7e6fb;
  border-radius: 24px;
  background:
    radial-gradient(circle at 13% 58%, rgba(220, 234, 255, .72), transparent 27%),
    linear-gradient(135deg, #fbfdff 0%, #fff 58%, #f4f8ff 100%);
  box-shadow: 0 18px 45px -36px rgba(28, 73, 145, .35);
}
.about-contact-section::before,
.about-contact-section::after {
  content: '';
  position: absolute;
  pointer-events: none;
  background: rgba(211, 226, 249, .42);
  transform: rotate(-33deg);
}
.about-contact-section::before { top: 38px; left: 48px; width: 112px; height: 28px; border-radius: 8px; }
.about-contact-section::after { top: 92px; left: 118px; width: 74px; height: 58px; border-radius: 22px; }
.about-contact-section .about-header-center { position: relative; z-index: 2; margin-bottom: 28px; }
.about-contact-section .about-section-title { font-size: clamp(26px, 2.1vw, 32px); }
.about-contact-section .about-section-subtitle { max-width: 760px; font-size: 15px; }
.about-contact {
  display: grid;
  position: relative;
  z-index: 1;
  grid-template-columns: minmax(230px, .95fr) minmax(250px, .95fr) minmax(340px, 1.25fr);
  gap: clamp(20px, 2.2vw, 32px);
  align-items: start;
  min-height: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}
.about-contact.is-no-qr { grid-template-columns: minmax(240px, .95fr) minmax(280px, 1.15fr) minmax(260px, .85fr); }
.about-contact-visual {
  position: relative;
  align-self: start;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  min-width: 0;
}
.about-contact-avatar {
  position: relative;
  z-index: 1;
  /* 100% กันภาพล้นออกนอกคอลัมน์จนไปทับข้อความ
     ส่วน height: auto ทำให้กล่องภาพพอดีกับรูป ไม่เหลือช่องว่างด้านล่าง */
  width: min(100%, 360px);
  height: auto;
  max-width: 100%;
  display: block;
  object-fit: contain;
  object-position: center top;
  border: 0;
  border-radius: 0;
  background: transparent;
  filter: drop-shadow(0 18px 18px rgba(37, 82, 151, .16));
}
.about-contact-body {
  min-width: 0;
  padding: 0;
}
.about-contact-name {
  margin: 0 0 12px;
  color: #0b1f3a;
  font-size: clamp(24px, 1.8vw, 29px);
  font-weight: 800;
  line-height: 1.22;
}
.about-contact-text { max-width: 46ch; margin: 0; color: #5a6a83; font-size: 13.5px; line-height: 1.72; text-wrap: pretty; }
.about-contact-quote {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 20px 0 0;
  padding: 14px 18px;
  border: 1px solid #e2ecfa;
  border-radius: 14px;
  background: #eef5ff;
}
.about-contact-quote > span {
  flex: 0 0 auto;
  color: #2878e7;
  font-family: Georgia, serif;
  font-size: 42px;
  font-weight: 700;
  line-height: .6;
  align-self: flex-start;
}
.about-contact-quote p { margin: 0; color: #23477e; font-size: 13.5px; font-style: italic; font-weight: 700; line-height: 1.5; }
.about-contact-connect {
  display: grid;
  grid-template-columns: minmax(190px, 1.2fr) minmax(150px, 1fr);
  gap: 20px;
  align-items: start;
  min-width: 0;
  padding-left: 24px;
}
.about-contact-actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  gap: 12px;
}
.about-contact-mail,
.about-contact-line,
.about-contact-fb {
  min-height: 64px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 11px;
  padding: 10px 12px;
  border: 1px solid #dfe7f2;
  border-radius: 14px;
  color: #1e65ca;
  background: rgba(255, 255, 255, .92);
  box-shadow: 0 8px 22px -18px rgba(25, 55, 101, .5);
  text-align: left;
  text-decoration: none;
  transition: transform var(--t-fast), border-color var(--t-fast), box-shadow var(--t-fast);
}
.about-contact-action-icon {
  width: 38px;
  height: 38px;
  display: inline-flex;
  flex: 0 0 38px;
  align-items: center;
  justify-content: center;
  color: #fff;
  border-radius: 50%;
  background: linear-gradient(145deg, #4498ff, #1769d9);
  box-shadow: 0 8px 16px -10px rgba(25, 105, 217, .8);
}
.about-contact-line { color: #079743; }
.about-contact-line .about-contact-action-icon { background: linear-gradient(145deg, #12cd66, #02a849); }
.about-contact-mail:hover,
.about-contact-line:hover,
.about-contact-fb:hover {
  color: inherit;
  border-color: #bcd3f4;
  background: #fff;
  box-shadow: 0 14px 28px -20px rgba(25, 55, 101, .62);
  transform: translateY(-2px);
  text-decoration: none;
}
.about-contact-mail small,
.about-contact-mail strong,
.about-contact-line small,
.about-contact-line strong,
.about-contact-fb small,
.about-contact-fb strong { display: block; }
.about-contact-mail small,
.about-contact-line small,
.about-contact-fb small { color: #58708f; font-size: 11px; font-weight: 600; line-height: 1.25; }
.about-contact-mail strong,
.about-contact-line strong,
.about-contact-fb strong { color: inherit; font-size: 14px; line-height: 1.35; }
/* An address is one long unbreakable word, so it gets room to sit inside the
   card instead of pushing the card wider. The break itself is the <wbr> the
   page puts before the @; anywhere-breaking is only the last resort for an
   address whose local part alone overflows. */
.about-contact-mail > span:last-child { min-width: 0; }
.about-contact-mail strong { font-size: 13.5px; overflow-wrap: break-word; }
.about-contact-qr { position: relative; gap: 8px; }
.about-qr-plate { padding: 14px; border-radius: 14px; }
.about-qr-plate img { width: 156px; height: 156px; }
.about-contact-qr figcaption { font-size: 11px; }
.about-contact-note {
  align-self: center;
  margin: 8px 0 0;
  color: #397bea;
  font-family: "Segoe Print", "Comic Sans MS", cursive;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.3;
  text-align: center;
  transform: rotate(3deg);
}
.about-contact-line:focus-visible,
.about-contact-fb:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 3px; }

@media (max-width: 1180px) {
  .about-contact {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas: "visual body" "connect connect";
    gap: 28px;
  }
  .about-contact-visual { grid-area: visual; min-height: 0; }
  .about-contact-avatar { width: min(100%, 320px); height: auto; }
  .about-contact-body { grid-area: body; align-self: start; padding: 0; }
  .about-contact-connect {
    grid-area: connect;
    align-self: start;
    padding-top: 24px;
    padding-left: 0;
    border-top: 1px solid #dbe6f5;
  }
}

@media (max-width: 992px) {
  .container-brand { padding-inline: 24px; }
  .about-hero { padding: 40px 32px 34px; margin-bottom: 38px; }
  .about-hero-content { max-width: 90%; }
  .about-hero-title { font-size: 29px; }
  .about-hero-letter-body { max-width: 100%; font-size: 15.5px; }
  .about-hero-closing { max-width: min(640px, 100%); }
  .about-values-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .about-contact-section { padding: 28px; }
  .about-contact-avatar { width: min(100%, 280px); height: auto; }
}

@media (max-width: 760px) {
  .about-hero { padding: 34px 26px 30px; }
  .about-hero-content { max-width: 100%; }
  .about-proof-note { display: none; }
}

@media (max-width: 640px) {
  .container-brand { padding-inline: 16px; }
  .about-hero { padding: 26px 22px 24px; margin: 10px 0 32px; border-radius: 18px; }
  .about-hero-content { width: 100%; max-width: 100%; padding: 0; }
  .about-hero-badge { margin-bottom: 12px; font-size: 12px; }
  .about-hero-title { margin-bottom: 12px; font-size: 24px; line-height: 1.3; }
  .about-hero-lead { font-size: 14.5px; line-height: 1.76; margin-bottom: 16px; }
  .about-hero-letter-body { font-size: 14px; line-height: 1.82; gap: 12px; }
  .about-hero-closing { width: 100%; max-width: 100%; margin-top: 18px; padding: 13px 16px; border-radius: 12px; }
  .about-hero-closing p { font-size: 13px; line-height: 1.68; }
  .about-hero-signature { margin-top: 18px; }
  .about-hero-signature-text { font-size: 13px; }
  .about-hero-signature-sub { font-size: 11px; }
  .about-section { margin-bottom: 38px; }
  .about-header-center { margin-bottom: 19px; }
  .about-section-title { font-size: 24px; }
  .about-section-subtitle { font-size: 13px; }
  .about-values-grid { grid-template-columns: minmax(0, 1fr); gap: 11px; }
  .about-value-card { min-height: 0; padding: 18px 16px; }
  .about-value-icon { width: 42px; height: 42px; }
  .about-value-title { font-size: 17px; }
  .about-proof { padding: 21px 14px 17px; border-radius: 17px; }
  .about-stats-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9px; }
  .about-stat-item { min-height: 108px; padding: 12px 8px; }
  .about-stat-num { font-size: 27px; }
  .about-contact-section { padding: 24px 16px 26px; border-radius: 18px; }
  .about-contact-section::before { left: -20px; }
  .about-contact-section::after { left: 18px; }
  .about-contact-section .about-header-center { margin-bottom: 18px; }
  .about-contact-section .about-section-title { font-size: 25px; }
  .about-contact { grid-template-columns: minmax(0, 1fr); grid-template-areas: none; gap: 24px; }
  .about-contact-visual,
  .about-contact-body,
  .about-contact-connect { grid-area: auto; }
  .about-contact-visual { min-height: 0; }
  .about-contact-avatar { width: min(100%, 300px); height: auto; }
  .about-contact-body { padding: 0; text-align: center; }
  .about-contact-name { font-size: 26px; }
  .about-contact-text { max-width: none; text-align: left; }
  .about-contact-quote { text-align: left; }
  .about-contact-connect { grid-template-columns: minmax(0, 1fr); gap: 20px; padding-top: 20px; }
  .about-contact-actions { width: 100%; }
  .about-contact-mail,
  .about-contact-line,
  .about-contact-fb { width: 100%; min-height: 58px; }
  .about-contact-qr { width: 100%; }
  /* Same quiet-zone rule on a phone, where the code is what actually gets
     scanned — off a second screen or across a table. */
  .about-qr-plate { padding: 16px; }
  .about-qr-plate img { width: min(200px, 58vw); height: min(200px, 58vw); }
}

:root[data-theme="dark"] .about-hero {
  background: var(--surface);
  border-color: var(--border);
  box-shadow: 0 8px 30px rgba(0, 0, 0, .25);
}
:root[data-theme="dark"] .about-hero-badge {
  background: rgba(56, 110, 227, 0.14);
  border-color: rgba(56, 110, 227, 0.32);
  color: #93b4fb;
}
:root[data-theme="dark"] .about-hero-title {
  color: var(--text);
}
:root[data-theme="dark"] .about-hero-lead {
  color: #c0cde5;
}
:root[data-theme="dark"] .about-hero-letter-body p {
  color: var(--text-muted);
}
:root[data-theme="dark"] .about-hero-closing {
  background: var(--surface-raised);
  border-color: var(--border);
}
:root[data-theme="dark"] .about-hero-closing p {
  color: var(--text);
}
:root[data-theme="dark"] .about-hero-signature-line {
  background: var(--border);
}
:root[data-theme="dark"] .about-hero-signature-text {
  color: #91adff;
}
:root[data-theme="dark"] .about-hero-signature-sub {
  color: var(--text-muted);
}
:root[data-theme="dark"] .about-contact-section { background: var(--surface); border-color: var(--border); }
:root[data-theme="dark"] .about-value-card:nth-child(n) { background: var(--surface); }
:root[data-theme="dark"] .about-proof { background: #101a33; border-color: var(--border); }
:root[data-theme="dark"] .about-contact-actions { border-color: var(--border); }
:root[data-theme="dark"] .about-contact-section {
  background: radial-gradient(circle at 13% 58%, rgba(45, 75, 124, .26), transparent 27%), var(--surface);
}
:root[data-theme="dark"] .about-contact-quote,
:root[data-theme="dark"] .about-contact-mail,
:root[data-theme="dark"] .about-contact-line,
:root[data-theme="dark"] .about-contact-fb { background: var(--surface-raised); border-color: var(--border); }
:root[data-theme="dark"] .about-contact-connect { border-color: var(--border); }
:root[data-theme="dark"] .about-contact-handwritten { color: #b9cff5; }

/* ==========================================================================
   PROMOTION CODE DIALOG
   ==========================================================================
   Three states in one dialog — enter a code, read what it would do, see what
   it did — built on the shared .modal-backdrop / .modal shell so it inherits
   the site's radius, shadow and entrance. What is added here is the accent
   discipline: navy while nothing has happened, green once the server has
   confirmed the code, and amber reserved for the membership benefit itself
   (the one place gold means "paid" across the whole product).

   No glass, no gradient sweep, no confetti: the numbers on this screen are
   the reason a person opened it, and every effect here is in service of
   reading them. */

/* The page behind a dialog must not scroll: on iOS a scrolling body drags the
   fixed backdrop with it. */
body.has-modal { overflow: hidden; }

.promo-modal {
  position: relative;
  max-width: 480px;
  padding: var(--space-md);
  border-color: var(--border-strong);
}

.promo-close {
  position: absolute; top: 10px; right: 10px;
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border: 0; border-radius: var(--radius-pill);
  background: transparent; color: var(--text-subtle);
  cursor: pointer; transition: background var(--t-fast), color var(--t-fast);
}
.promo-close:hover { background: var(--surface-hover); color: var(--text); }

/* -------------------------------------------------------------------- head */

.promo-head { text-align: center; padding: var(--space-2xs) 0 var(--space); }

.promo-mark {
  width: 52px; height: 52px; margin: 0 auto var(--space-sm);
  display: grid; place-items: center;
  border-radius: var(--radius);
  background: var(--primary-soft); color: var(--primary);
  border: 1px solid var(--primary-border);
}
.promo-mark-ok {
  background: var(--success-soft); color: var(--success);
  border-color: var(--success-border);
}
/* One short check, once. A success state that keeps moving reads as unfinished. */
.promo-mark-pop { animation: promo-pop 380ms var(--spring) both; }
@keyframes promo-pop { from { transform: scale(.6); opacity: 0; } }

.promo-head h3 { margin: 0; font-size: 19px; letter-spacing: -.01em; }
.promo-head p {
  margin: 6px auto 0; max-width: 34ch;
  font-size: 13.5px; line-height: 1.55; color: var(--text-muted);
}

.promo-code-chip {
  display: inline-block; margin-top: 10px;
  padding: 5px 13px; border-radius: var(--radius-pill);
  background: var(--surface-muted); border: 1px solid var(--border);
  font-size: 14px; font-weight: 700; letter-spacing: .06em;
  color: var(--text);
}

/* -------------------------------------------------------------------- form */

.promo-form .form-group { margin-bottom: var(--space-xs); }
.promo-input {
  text-align: center;
  /* 16px minimum: anything smaller makes iOS Safari zoom the page on focus. */
  font-size: 17px; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase;
}
.promo-input::placeholder {
  font-weight: 500; letter-spacing: .04em; text-transform: none;
}

.promo-error {
  margin: 0 0 var(--space-xs);
  padding: 9px 12px; border-radius: var(--radius-sm);
  background: var(--danger-soft); border: 1px solid var(--danger-border);
  color: var(--danger); font-size: 13px; line-height: 1.5;
}

/* ----------------------------------------------------------------- benefit */

.promo-benefit {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  padding: 13px var(--space-sm); margin-bottom: var(--space-sm);
  border-radius: var(--radius);
  background: var(--vip-soft); border: 1px solid var(--vip-border);
  color: var(--vip-strong);
}
.promo-benefit b { font-size: 16.5px; }
.promo-benefit-icon { display: grid; place-items: center; }

/* ------------------------------------------------------------------- facts */

.promo-facts {
  margin: 0 0 var(--space-sm);
  border: 1px solid var(--border); border-radius: var(--radius);
  overflow: hidden;
}
.promo-facts > div {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--space-sm);
  padding: 11px var(--space-sm);
  border-bottom: 1px solid var(--border);
}
.promo-facts > div:last-child { border-bottom: 0; }
/* display:flex above outranks the user agent [hidden] rule, so the row
   that only applies to a current member has to be told again. */
.promo-facts > div[hidden] { display: none; }
.promo-facts dt { margin: 0; font-size: 13px; color: var(--text-muted); }
.promo-facts dd {
  margin: 0; font-size: 14px; font-weight: 600; color: var(--text);
  text-align: right;
}
/* The line a person actually came for. */
.promo-fact-strong { background: var(--success-soft); }
.promo-fact-strong dt { color: var(--success); font-weight: 600; }
.promo-fact-strong dd { color: var(--success); font-size: 15.5px; font-weight: 700; }

.promo-note {
  margin: 0 0 var(--space-sm);
  display: flex; align-items: flex-start; gap: 6px;
  font-size: 12.5px; line-height: 1.5; color: var(--text-subtle);
}
.promo-note .icon { flex: 0 0 auto; margin-top: 2px; }

/* ----------------------------------------------------------------- actions */

.promo-actions { display: flex; gap: 9px; }
/* The confirming action carries the weight; the way back stays available but
   does not compete for it. */
.promo-actions .btn { flex: 1 1 0; min-width: 0; justify-content: center; }
.promo-actions .btn-primary { flex: 1.4 1 0; }

/* --------------------------------------------------------------- responsive */

@media (max-width: 520px) {
  .promo-backdrop { padding: 12px; align-items: end; }
  .promo-modal {
    max-width: none;
    padding: var(--space) var(--space) calc(var(--space) + env(safe-area-inset-bottom));
    max-height: calc(100vh - 24px);
  }
  .promo-head h3 { font-size: 18px; }
  /* Stacked, with the confirming action on top of the thumb rather than
     under it. */
  .promo-actions { flex-direction: column-reverse; }
  .promo-actions .btn { width: 100%; flex: 0 0 auto; }
  .promo-facts > div { padding: 10px var(--space-sm); }
}

/* A plain-text control that has to sit in a list of links. */
.footer-link-btn {
  padding: 0; border: 0; background: none;
  font: inherit; color: inherit; cursor: pointer; text-align: left;
}
.footer-link-btn:hover { color: var(--text-inverse); text-decoration: underline; }

/* -------------------------------------------------------------------- dark */

:root[data-theme="dark"] .promo-mark { background: rgba(28, 71, 204, .18); border-color: rgba(120, 150, 255, .3); }
:root[data-theme="dark"] .promo-mark-ok { background: rgba(21, 163, 74, .16); border-color: rgba(90, 200, 140, .32); }
:root[data-theme="dark"] .promo-benefit { background: rgba(217, 119, 6, .14); border-color: rgba(240, 205, 148, .3); }
:root[data-theme="dark"] .promo-fact-strong { background: rgba(21, 163, 74, .12); }
:root[data-theme="dark"] .promo-error { background: rgba(220, 38, 38, .14); border-color: rgba(247, 195, 195, .3); }

/* ==========================================================================
   PROMOTION POPUP SYSTEM (SIMPLIFIED IMAGE-CENTRIC)
   ========================================================================== */

.promo-popup-backdrop {
  position: fixed; inset: 0; z-index: 350;
  background: rgba(15, 23, 42, .65);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  display: flex; align-items: center; justify-content: center;
  padding: 24px 16px;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.promo-popup-backdrop[hidden] { display: none !important; }

.promo-popup-modal {
  position: relative;
  width: 100%;
  max-width: min(90vw, 680px);
  margin: auto;
  background: var(--surface, #ffffff);
  border: 1px solid rgba(0, 0, 0, .08);
  border-radius: 20px;
  box-shadow: 0 25px 60px -15px rgba(10, 25, 60, .36), 0 4px 16px rgba(0, 0, 0, .08);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 44px);
  animation: promo-popup-scale 220ms cubic-bezier(.16, 1, .3, 1) both;
}

@keyframes promo-popup-scale {
  from { opacity: 0; transform: scale(.98); }
  to   { opacity: 1; transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .promo-popup-modal { animation: none; }
}

/* Floating top-right close button (X) */
.promo-popup-close {
  position: absolute; top: 12px; right: 12px; z-index: 30;
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(0, 0, 0, .12);
  border-radius: 50%;
  background: #ffffff;
  color: #0f172a;
  cursor: pointer;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .18), 0 1px 3px rgba(0, 0, 0, .08);
  transition: transform 160ms ease, background 160ms ease, color 160ms ease, box-shadow 160ms ease;
  -webkit-tap-highlight-color: transparent;
  padding: 0;
}
.promo-popup-close:hover {
  background: #ffffff;
  color: #000000;
  transform: scale(1.06);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .24);
}
.promo-popup-close:active {
  transform: scale(.96);
}
.promo-popup-close:focus-visible {
  outline: 2px solid var(--primary, #1c47cc);
  outline-offset: 2px;
}
.promo-popup-close .icon {
  width: 22px;
  height: 22px;
  stroke-width: 2.2;
}

/* Promotion card container */
.promo-simple-card {
  display: flex;
  flex-direction: column;
  width: 100%;
  min-height: 0;
  flex: 1 1 auto;
}

.promo-simple-body {
  position: relative;
  width: 100%;
  background: #ffffff;
  display: block;
  line-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  flex: 1 1 auto;
  min-height: 0;
}
.promo-simple-body::-webkit-scrollbar {
  width: 6px;
}
.promo-simple-body::-webkit-scrollbar-track {
  background: transparent;
}
.promo-simple-body::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, .2);
  border-radius: 4px;
}

.promo-simple-link {
  display: block;
  text-decoration: none;
  cursor: pointer;
  line-height: 0;
  width: 100%;
  transition: opacity 150ms ease;
}
.promo-simple-link:hover {
  opacity: .97;
}

.promo-simple-img {
  width: 100%;
  height: auto;
  max-width: 100%;
  display: block;
  object-fit: contain;
  border-top-left-radius: inherit;
  border-top-right-radius: inherit;
}

/* Footer: Don't show again today checkbox */
.promo-simple-foot {
  padding: 13px 20px;
  background: var(--surface, #ffffff);
  border-top: 1px solid var(--border-subtle, #e2e8f0);
  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex-shrink: 0;
}

.promo-simple-dismiss-label {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  font-weight: 500;
  color: var(--text-muted, #64748b);
  cursor: pointer;
  user-select: none;
  line-height: 1.4;
  transition: color 150ms ease;
}
.promo-simple-dismiss-label:hover {
  color: var(--text, #1e293b);
}

.promo-simple-checkbox {
  width: 18px;
  height: 18px;
  accent-color: var(--primary, #1c47cc);
  cursor: pointer;
  margin: 0;
  border-radius: 4px;
}

/* Tablet / iPad responsive */
@media (max-width: 1024px) {
  .promo-popup-modal {
    max-width: min(82vw, 640px);
  }
}

/* Mobile responsive */
@media (max-width: 540px) {
  .promo-popup-backdrop {
    padding: 16px 12px;
  }
  .promo-popup-modal {
    max-width: 92vw;
    border-radius: 16px;
  }
  .promo-popup-close {
    top: 10px;
    right: 10px;
    width: 44px;
    height: 44px;
  }
  .promo-simple-foot {
    padding: 11px 16px;
  }
  .promo-simple-dismiss-label {
    font-size: 13.5px;
    gap: 8px;
  }
}

/* Dark mode */
:root[data-theme="dark"] .promo-popup-modal {
  background: var(--surface, #131d36);
  border-color: var(--border-strong, #2b395e);
  box-shadow: 0 25px 60px -15px rgba(0, 0, 0, .8), 0 0 0 1px rgba(255, 255, 255, .08);
}
:root[data-theme="dark"] .promo-simple-body {
  background: #0d162a;
}
:root[data-theme="dark"] .promo-simple-body::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, .2);
}
:root[data-theme="dark"] .promo-simple-foot {
  background: var(--surface, #131d36);
  border-top-color: var(--border-subtle, #1e2c4f);
}
:root[data-theme="dark"] .promo-popup-close {
  background: #1e293b;
  border-color: rgba(255, 255, 255, .2);
  color: #f8fafc;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .4);
}
:root[data-theme="dark"] .promo-popup-close:hover {
  background: #334155;
  color: #ffffff;
}
:root[data-theme="dark"] .promo-simple-dismiss-label:hover {
  color: var(--text, #f1f5f9);
}

/* ============================================================================
   FLOATING FEEDBACK MASCOT
   One global, low-distraction entry point. The mascot is bare artwork; only
   the requested panel uses a surface.
   ============================================================================ */
.feedback-widget {
  position: fixed;
  right: 20px;
  bottom: 18px;
  z-index: 240;
  width: 138px;
  height: 145px;
  pointer-events: none;
}

.feedback-mascot {
  position: absolute;
  inset: 0;
  display: block;
  width: 138px;
  height: 145px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  pointer-events: auto;
  z-index: 1;
  filter: drop-shadow(0 8px 12px rgba(12, 23, 48, .18));
  transition: transform var(--t), filter var(--t);
}
.feedback-mascot img { display: block; width: 100%; height: 100%; object-fit: contain; }
.feedback-mascot:hover { transform: translateY(-3px) scale(1.035); filter: drop-shadow(0 12px 14px rgba(12, 23, 48, .24)); }
.feedback-mascot:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 4px; border-radius: 26px; }
.feedback-mascot[aria-expanded="true"] { transform: translateY(-2px) scale(1.02); }

.feedback-tooltip {
  position: absolute;
  right: 6px;
  bottom: calc(100% + 8px);
  width: max-content;
  max-width: min(260px, calc(100vw - 32px));
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-sm);
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.35;
  opacity: 0;
  visibility: hidden;
  transform: translateY(4px);
  pointer-events: none;
  z-index: 2;
  transition: opacity var(--t-fast), transform var(--t-fast), visibility var(--t-fast);
}
.feedback-mascot:hover + .feedback-tooltip,
.feedback-mascot:focus-visible + .feedback-tooltip { opacity: 1; visibility: visible; transform: translateY(0); }

.feedback-scrim {
  position: fixed;
  inset: 0;
  z-index: -1;
  background: transparent;
  pointer-events: auto;
}

.feedback-panel {
  position: absolute;
  right: 0;
  bottom: calc(100% + 14px);
  width: 710px;
  max-width: calc(100vw - 48px);
  max-height: min(790px, calc(100vh - 190px));
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 2px solid rgba(255, 255, 255, .94);
  outline: 1px solid #d5e2f3;
  border-radius: 30px;
  background: #ffffff;
  color: #0f172a;
  box-shadow: 0 30px 70px -18px rgba(15, 42, 82, .24), 0 8px 24px -8px rgba(15, 23, 42, .12);
  pointer-events: auto;
  overscroll-behavior: contain;
  z-index: 3;
}
.feedback-panel:not([hidden]) {
  animation: feedbackPanelSlideUp 0.22s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes feedbackPanelSlideUp {
  from { opacity: 0; transform: translateY(12px) scale(0.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
.feedback-panel[hidden], .feedback-scrim[hidden], .feedback-step[hidden] { display: none !important; }

/* Header */
.feedback-panel-head {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  min-height: 244px;
  padding: 30px 28px 0 40px;
  background:
    radial-gradient(circle at 76% 26%, rgba(180, 214, 255, .44), transparent 32%),
    linear-gradient(145deg, #f2f8ff 0%, #eaf4ff 54%, #f9fcff 100%);
  border-bottom: none;
  flex-shrink: 0;
}
.feedback-head-text {
  flex: 1;
  min-width: 0;
  padding-bottom: 30px;
  padding-right: 275px;
  z-index: 2;
}
.feedback-kicker {
  display: inline-flex;
  align-items: center;
  margin-bottom: 17px;
  padding: 6px 16px;
  border-radius: 999px;
  background: #e1effe;
  color: #2563eb;
  font: 800 15px/1.35 var(--font-num, system-ui);
  letter-spacing: .08em;
  text-transform: uppercase;
}
.feedback-panel-head h2 {
  margin: 0 0 10px;
  color: #0f172a;
  font-size: 32px;
  font-weight: 800;
  line-height: 1.25;
}
.feedback-subtitle {
  margin: 0;
  color: #64748b;
  font-size: 18px;
  font-weight: 500;
  line-height: 1.55;
}

/* Mascot visual in header */
.feedback-head-visual {
  position: absolute;
  right: 18px;
  bottom: 10px;
  width: 280px;
  height: 189px;
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  pointer-events: none;
  z-index: 1;
}
.feedback-head-mascot {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

.feedback-close {
  position: absolute;
  top: 18px;
  right: 18px;
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  padding: 0;
  border: 1px solid #e2e8f0;
  border-radius: 16px;
  background: #ffffff;
  color: #64748b;
  cursor: pointer;
  transition: all var(--t-fast);
  z-index: 5;
}
.feedback-close:hover {
  background: #f8fafc;
  color: #0f172a;
  border-color: #cbd5e1;
}
.feedback-close:focus-visible, .feedback-back:focus-visible, .feedback-options button:focus-visible, .feedback-upload:has(input:focus-visible) { outline: 3px solid var(--focus-ring); outline-offset: 2px; }

/* Choose step & Cards */
.feedback-step[data-feedback-step="choose"] {
  position: relative;
  margin-top: -12px;
  padding: 20px 26px 22px;
  border-radius: 30px 30px 0 0;
  background: #ffffff;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.feedback-options {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.feedback-options button.feedback-card {
  display: grid;
  grid-template-columns: 68px minmax(0, 1fr) 24px;
  align-items: center;
  gap: 20px;
  width: 100%;
  min-height: 104px;
  padding: 14px 24px;
  border: 1px solid #dbe5f1;
  border-radius: 23px;
  background: #ffffff;
  color: #0f172a;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
  box-shadow: 0 5px 18px -14px rgba(15, 46, 94, .22);
}
.feedback-options button.feedback-card:hover {
  border-color: #cbd5e1;
  background: #fafbfc;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.05);
}
.feedback-options button.feedback-card:active {
  transform: translateY(0);
}

.feedback-option-icon {
  width: 68px;
  height: 68px;
  min-width: 68px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  flex-shrink: 0;
}
.feedback-option-icon .icon,
.feedback-option-icon svg { width: 32px; height: 32px; }
.feedback-icon-bug {
  background: #fee2e2;
}
.feedback-icon-content {
  background: #fef3c7;
  color: #f59e0b;
}
.feedback-icon-suggestion {
  background: #dbeafe;
  color: #3b82f6;
}

.feedback-option-body {
  min-width: 0;
}
.feedback-option-title {
  display: block;
  font-size: 22px;
  font-weight: 750;
  color: #0f172a;
  line-height: 1.35;
  margin-bottom: 5px;
}
.feedback-option-desc {
  display: block;
  font-size: 16px;
  color: #64748b;
  line-height: 1.45;
}
.feedback-option-chevron {
  color: #94a3b8;
  flex-shrink: 0;
  width: 24px;
  height: 24px;
}

/* Footer inside choose step */
.feedback-panel-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  margin-top: 16px;
  padding: 4px 8px 0;
  border-top: none;
  font-size: 16px;
}
.feedback-footer-contact {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: #2563eb;
  font-weight: 600;
  text-decoration: none;
  transition: opacity var(--t-fast);
}
.feedback-footer-contact:hover {
  opacity: 0.85;
  text-decoration: none;
}
.feedback-footer-contact .icon {
  color: #2563eb;
}
.feedback-footer-thanks {
  color: #64748b;
  font-size: 15px;
  font-style: italic;
  font-weight: 500;
}

/* Form step */
.feedback-form {
  padding: 20px 22px 22px;
  background: #ffffff;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.feedback-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 16px;
  padding: 6px 12px;
  border: 1px solid #e2e8f0;
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
  color: var(--text);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: all var(--t-fast);
}
.feedback-back:hover {
  background: var(--surface-hover);
  color: var(--primary);
}
.feedback-selected {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  margin-bottom: 16px;
  border: 1px solid var(--primary-border);
  border-radius: var(--radius-sm);
  background: var(--primary-soft);
}
.feedback-selected > span:first-child { font-size: 22px; }
.feedback-selected small, .feedback-selected b { display: block; }
.feedback-selected small { color: var(--text-muted); font-size: 11px; }
.feedback-selected b { color: var(--primary-dark); font-size: 14px; }
.feedback-form .form-group { margin-bottom: 14px; }
.feedback-form textarea { min-height: 110px; max-height: 220px; resize: vertical; }
.feedback-field-error { display: block; min-height: 18px; margin-top: 4px; color: var(--danger); font-size: 11.5px; }
.feedback-upload {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 56px;
  padding: 10px 14px;
  border: 1.5px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-muted);
  color: var(--text-muted);
  cursor: pointer;
  transition: border-color var(--t-fast), color var(--t-fast);
}
.feedback-upload:hover { border-color: var(--primary); color: var(--primary); }
.feedback-upload span { min-width: 0; }
.feedback-upload b, .feedback-upload small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.feedback-upload b { color: var(--text); font-size: 13px; }
.feedback-upload small { margin-top: 2px; font-size: 11px; }
.feedback-error { margin: 0 0 14px; padding: 10px 14px; border: 1px solid var(--danger-border); border-radius: var(--radius-sm); background: var(--danger-soft); color: var(--danger); font-size: 12.5px; line-height: 1.45; }
.feedback-submit {
  width: 100%;
  height: 46px;
  border-radius: var(--radius-sm);
  font-size: 14.5px;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.feedback-success { padding: 40px 24px; text-align: center; }
.feedback-success-mark { display: grid; place-items: center; width: 60px; height: 60px; margin: 0 auto 16px; border-radius: 50%; background: var(--success-soft); color: var(--success); }
.feedback-success h3 { margin: 0 0 8px; font-size: 21px; }
.feedback-success p { margin: 0 0 22px; color: var(--text-muted); font-size: 14.5px; }

/* Dark mode overrides for panel and header */
:root[data-theme="dark"] .feedback-panel {
  background: #0f172a;
  border-color: rgba(255, 255, 255, 0.1);
  box-shadow: 0 20px 48px -12px rgba(0, 0, 0, 0.5);
  color: #f1f5f9;
}
:root[data-theme="dark"] .feedback-panel-head {
  background: linear-gradient(180deg, #132247 0%, #0d1935 65%, #0f172a 100%);
}
:root[data-theme="dark"] .feedback-panel-head h2 { color: #f1f5f9; }
:root[data-theme="dark"] .feedback-subtitle { color: #94a3b8; }
:root[data-theme="dark"] .feedback-kicker {
  background: rgba(37, 99, 235, 0.25);
  color: #93c5fd;
}
:root[data-theme="dark"] .feedback-close {
  background: #1e293b;
  border-color: rgba(255, 255, 255, 0.1);
  color: #94a3b8;
}
:root[data-theme="dark"] .feedback-close:hover {
  background: #334155;
  color: #f8fafc;
}
:root[data-theme="dark"] .feedback-step[data-feedback-step="choose"],
:root[data-theme="dark"] .feedback-form {
  background: #0f172a;
}
:root[data-theme="dark"] .feedback-options button.feedback-card {
  background: #1e293b;
  border-color: rgba(255, 255, 255, 0.08);
  color: #f1f5f9;
}
:root[data-theme="dark"] .feedback-options button.feedback-card:hover {
  background: #25334d;
  border-color: rgba(255, 255, 255, 0.16);
}
:root[data-theme="dark"] .feedback-option-title { color: #f1f5f9; }
:root[data-theme="dark"] .feedback-option-desc { color: #94a3b8; }
:root[data-theme="dark"] .feedback-icon-bug {
  background: rgba(239, 68, 68, 0.2);
}
:root[data-theme="dark"] .feedback-icon-content {
  background: rgba(245, 158, 11, 0.2);
}
:root[data-theme="dark"] .feedback-icon-suggestion {
  background: rgba(59, 130, 246, 0.2);
}
:root[data-theme="dark"] .feedback-footer-contact {
  color: #60a5fa;
}
:root[data-theme="dark"] .feedback-footer-contact .icon {
  color: #60a5fa;
}
:root[data-theme="dark"] .feedback-footer-thanks {
  color: #94a3b8;
}

/* Admin inbox and detail reuse the existing cards, table and forms. */
.admin-nav-count { min-width: 21px; margin-left: auto; padding: 1px 6px; border-radius: var(--radius-pill); background: var(--danger); color: #fff; font: 700 10px/18px var(--font-num); text-align: center; }
.feedback-admin-table td { vertical-align: middle; }
.feedback-admin-table td small { display: block; max-width: 300px; margin-top: 3px; color: var(--text-subtle); font-size: 11.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.feedback-type-dot { display: inline-block; width: 8px; height: 8px; margin-right: 7px; border-radius: 50%; background: var(--text-subtle); }
.feedback-type-dot.is-bug { background: var(--danger); }
.feedback-type-dot.is-content { background: var(--warning); }
.feedback-type-dot.is-suggestion { background: var(--primary); }
.feedback-admin-detail { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: var(--space-md); align-items: start; }
.feedback-admin-action { position: sticky; top: 82px; }
.feedback-admin-message { margin: 0; color: var(--text); font-size: 16px; line-height: 1.75; overflow-wrap: anywhere; }
.feedback-admin-attachment { display: inline-grid; gap: 7px; margin-top: 18px; color: var(--primary); font-size: 12.5px; font-weight: 600; }
.feedback-admin-attachment img { display: block; width: min(100%, 540px); max-height: 420px; object-fit: contain; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-muted); }
.feedback-meta-list { display: grid; gap: 0; }
.feedback-meta-list > div { display: grid; grid-template-columns: 130px minmax(0, 1fr); gap: 4px 14px; padding: 12px 0; border-bottom: 1px solid var(--border); }
.feedback-meta-list > div:last-child { border-bottom: 0; }
.feedback-meta-list span { grid-row: 1 / span 2; color: var(--text-subtle); font-size: 12px; }
.feedback-meta-list b { font-size: 13.5px; overflow-wrap: anywhere; }
.feedback-meta-list a, .feedback-meta-list small { color: var(--text-muted); font-size: 11.5px; overflow-wrap: anywhere; }
.feedback-reference-list { display: grid; gap: 9px; }
.feedback-reference-list a { display: grid; gap: 4px; padding: 11px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text); }
.feedback-reference-list a:hover { border-color: var(--primary-border); background: var(--surface-hover); text-decoration: none; }
.feedback-reference-list span { display: flex; align-items: center; gap: 7px; font-weight: 650; }
.feedback-reference-list small { color: var(--text-muted); }

@media (max-width: 900px) {
  .feedback-admin-detail { grid-template-columns: 1fr; }
  .feedback-admin-action { position: static; }
}

@media (max-width: 820px) and (min-width: 641px) {
  .feedback-panel { width: 620px; }
  .feedback-panel-head { min-height: 210px; padding: 26px 24px 0 30px; }
  .feedback-head-text { padding-right: 230px; padding-bottom: 24px; }
  .feedback-kicker { margin-bottom: 12px; font-size: 13px; }
  .feedback-panel-head h2 { font-size: 27px; }
  .feedback-subtitle { font-size: 15px; }
  .feedback-head-visual { width: 245px; height: 165px; bottom: 10px; }
  .feedback-head-mascot { width: 100%; height: 100%; }
  .feedback-options button.feedback-card {
    grid-template-columns: 60px minmax(0, 1fr) 20px;
    min-height: 96px;
    gap: 16px;
    padding: 14px 20px;
  }
  .feedback-option-icon { width: 60px; height: 60px; min-width: 60px; }
  .feedback-option-title { font-size: 19px; }
  .feedback-option-desc { font-size: 13.5px; }
  .feedback-panel-footer { font-size: 14px; }
  .feedback-footer-thanks { font-size: 13px; }
}

@media (max-width: 640px) {
  .feedback-widget {
    right: 12px;
    bottom: calc(10px + env(safe-area-inset-bottom));
    width: 84px;
    height: 88px;
  }
  .exam-runner-body .feedback-widget,
  .mock-body .feedback-widget { bottom: calc(70px + env(safe-area-inset-bottom)); }
  .feedback-mascot { width: 84px; height: 88px; filter: drop-shadow(0 6px 7px rgba(12, 23, 48, .17)); }
  .feedback-tooltip { display: none; }
  .feedback-scrim { background: rgba(6, 11, 26, .48); backdrop-filter: blur(2px); }
  .feedback-panel {
    position: fixed;
    inset: auto 0 0 0;
    width: 100%;
    max-width: none;
    max-height: min(88vh, 740px);
    border-width: 1px 0 0;
    border-radius: 24px 24px 0 0;
    padding-bottom: env(safe-area-inset-bottom);
  }
  .feedback-panel:not([hidden]) {
    animation: feedbackPanelSheetUp 0.26s cubic-bezier(0.16, 1, 0.3, 1);
  }
  @keyframes feedbackPanelSheetUp {
    from { transform: translateY(100%); }
    to { transform: translateY(0); }
  }
  .feedback-panel-head {
    min-height: 150px;
    padding: 18px 16px 0;
  }
  .feedback-head-text {
    padding: 0 0 14px;
    padding-right: 125px;
  }
  .feedback-panel-head h2 {
    font-size: 18px;
  }
  .feedback-kicker { margin-bottom: 8px; padding: 3px 12px; font-size: 11px; }
  .feedback-subtitle {
    font-size: 12px;
  }
  .feedback-head-visual {
    width: 150px;
    height: 101px;
    right: 4px;
    bottom: 0;
  }
  .feedback-head-mascot {
    width: 100%;
    height: 100%;
  }
  .feedback-close {
    top: 12px;
    right: 12px;
    width: 32px;
    height: 32px;
  }
  .feedback-step[data-feedback-step="choose"], .feedback-form {
    margin-top: 0;
    padding: 16px 18px calc(18px + env(safe-area-inset-bottom));
    border-radius: 20px 20px 0 0;
  }
  .feedback-options button.feedback-card {
    grid-template-columns: 42px minmax(0, 1fr) 18px;
    min-height: 74px;
    padding: 12px 14px;
    border-radius: 16px;
    gap: 12px;
  }
  .feedback-option-icon {
    width: 42px;
    height: 42px;
    min-width: 42px;
  }
  .feedback-option-icon .icon,
  .feedback-option-icon svg { width: 24px; height: 24px; }
  .feedback-option-title {
    font-size: 14.5px;
  }
  .feedback-option-desc {
    font-size: 11.5px;
  }
  .feedback-panel-footer {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    margin-top: 14px;
    padding-top: 12px;
    font-size: 12.5px;
  }
  .feedback-footer-thanks {
    align-self: flex-start;
    font-size: 12px;
  }
  .feedback-is-open {
    overflow: hidden;
  }
  .feedback-meta-list > div {
    grid-template-columns: 94px minmax(0, 1fr);
  }
}

@media (prefers-reduced-motion: reduce) {
  .feedback-mascot, .feedback-tooltip, .feedback-options button, .feedback-panel:not([hidden]) {
    animation: none !important;
    transition: none !important;
  }
}

@media print {
  .feedback-widget { display: none !important; }
}

/* A button whose label is content rather than a command — a หัวข้อ or วิชา
   name — and so may wrap. `.btn` is nowrap by design; this opts one button
   out without loosening the rule for every button on the site. */
.btn-wrap {
  max-width: 100%;
  white-space: normal;
  text-align: left;
  line-height: 1.5;
  height: auto;
  min-height: 40px;
  padding-block: 9px;
}

/* ------------------------------------- Written-examination qualification */
/* The verdict across every ภาค of one สนาม. Deliberately quieter than the
   score ring above it: this is a status, not a celebration, and it stops at
   "eligible for ภาค ค" because ภาค ค is never simulated here. */
.mock-qual {
  margin: 0 0 var(--space);
  padding: var(--space);
  text-align: left;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface-muted);
}
.mock-qual-head {
  display: flex; align-items: center; gap: 8px;
  font-size: 15px; line-height: 1.5;
}
.mock-qual-qualified     { border-color: color-mix(in srgb, var(--success) 40%, var(--border)); }
.mock-qual-qualified .mock-qual-head { color: var(--success); }
.mock-qual-not_qualified { border-color: color-mix(in srgb, var(--danger) 40%, var(--border)); }
.mock-qual-not_qualified .mock-qual-head { color: var(--danger); }
.mock-qual-incomplete .mock-qual-head { color: var(--text-muted); }

.mock-qual-parts { margin: var(--space-sm) 0 0; padding: 0; list-style: none; }
.mock-qual-parts li {
  display: flex; flex-wrap: wrap; gap: 4px 12px; justify-content: space-between;
  padding: 7px 0;
  font-size: 13.5px;
}
.mock-qual-parts li + li { border-top: 1px solid var(--hairline); }
.mock-qual-parts .k { color: var(--text-muted); min-width: 0; }
.mock-qual-parts .v { font-weight: 700; font-variant-numeric: tabular-nums; }
.mock-qual-parts .v small { font-weight: 500; color: var(--text-subtle); }
.mock-qual-parts .is-met .v { color: var(--success); }
.mock-qual-parts .is-missed .v { color: var(--danger); }
.mock-qual-parts .is-pending .v { color: var(--text-subtle); font-weight: 600; }

.mock-qual-note {
  display: flex; align-items: flex-start; gap: 6px;
  margin: var(--space-sm) 0 0;
  color: var(--text-subtle);
  font-size: 12px; line-height: 1.7;
}
.mock-qual-note .icon { flex: 0 0 auto; margin-top: 3px; }

/* ===========================================================================
   DAILY + ARTICLES HERO — same proportional scale system as the home hero
   ---------------------------------------------------------------------------
   Measured masters at viewport 768 (both cards are 689px wide there):
     .daily-hero    689 x 265.03  -> ratio 2.5997, copy 57.1%, 40% art reserve
     .articles-hero 689 x 212     -> ratio 3.25,   copy 55.84%, visual 67.8%

   Same two mechanics as the home hero: lock each card to its own master
   aspect-ratio so the artwork crop stops changing with the viewport, and drive
   every inner value from one scale — 1cqw = 1% of the real card width, with
   each number written as its master pixel size over the 689px master card.
   These rules come last in the file so they win over the older phone blocks
   without those needing to be unpicked rule by rule.
   =========================================================================== */
@media (max-width: 768px) {
  /* Query containers, scoped so no other .container is affected. */
  .daily-hub > .container.daily-shell { container-type: inline-size; }
  .container.articles-page { container-type: inline-size; }

  .daily-hero {
    aspect-ratio: 689 / 265.03;
    min-height: 0;
    padding: 3.4833cqw 40% 3.4833cqw 2.6125cqw;
    border-radius: 2.9028cqw;
  }
  .daily-hero-title { font-size: 3.7735cqw; line-height: 1.26; margin-bottom: 1.4514cqw; }
  .daily-hero-lead { font-size: 1.8577cqw; line-height: 1.55; margin-bottom: 1.7417cqw; }
  .daily-hero-benefits { gap: 1.1611cqw 1.7417cqw; margin-top: 0.8708cqw; }
  .daily-benefit-item { gap: 1.0159cqw; }
  .benefit-icon-wrap { width: 4.3542cqw; height: 4.3542cqw; border-radius: 1.1611cqw; }
  .benefit-icon-wrap svg { width: 2.1771cqw; height: 2.1771cqw; }
  .benefit-title { font-size: 1.7121cqw; }
  .benefit-desc { font-size: 1.5238cqw; }

  .articles-hero {
    aspect-ratio: 689 / 212;
    height: auto;
    min-height: 0;
    border-radius: 2.3222cqw;
  }
  .articles-hero-copy { width: 55.84%; padding: 2.9028cqw 0 2.9028cqw 3.4833cqw; }
  .articles-hero-visual { width: 67.8%; }
  .articles-hero-visual img { height: 100%; min-height: 0; }
  .articles-hero h1 { font-size: 4.2090cqw; line-height: 1.15; margin-bottom: 0.7257cqw; }
  .articles-hero-lead { font-size: 2.0319cqw; line-height: 1.5; margin-bottom: 0.7257cqw; }
  /* 1.5 rather than the master 1.6: sub-pixel rounding at this scale left the
     copy ~2.4px taller than the locked box, and the line-height is where that
     is cheapest to recover. */
  .articles-hero-description { font-size: 1.7417cqw; line-height: 1.5; }
  .articles-hero-points { font-size: 1.5965cqw; gap: 1.4514cqw 2.6125cqw; }
  .articles-hero-points .icon { width: 2.0319cqw; height: 2.0319cqw; }
}

@media (max-width: 768px) {
  /* The eyebrow was the one child left out of the scale system, so it stayed
     at its master pixel size while everything around it shrank and pushed the
     copy past the bottom of the locked box. */
  .articles-hero .articles-eyebrow {
    /* One line, as in the master — at this size the label otherwise wrapped
       and cost the locked box more height than it had. */
    white-space: nowrap;
    font-size: 1.7417cqw;
    padding: 0.5805cqw 1.5965cqw;
    border-radius: 2.9028cqw;
    margin-bottom: 0.7257cqw;
  }
  /* Both of these were phone-only rules that changed where the text breaks,
     which is a composition change: the headline gained a second line and the
     description lost its authored break. The master does neither. */
  /* The eyebrow icon was the last unscaled child — a fixed-size SVG holding
     the pill open and costing the locked box exactly the height it lacked. */
  .articles-hero .articles-eyebrow .icon { width: 2.0319cqw; height: 2.0319cqw; }
  .articles-hero h1 span { display: inline; }
  .articles-hero-description br { display: inline; }
}
