/* =====================================================================
   /avatar-frame — pixel-reference redesign (desktop = source of truth).
   Brand color: Velamart primary blue #1c48c1 only (per "chỉ dùng màu thương
   hiệu Velamart" final-polish pass) — all interactive/accent states below
   route through --af-primary/--af-accent, so repointing those two variables
   here is the single source of truth for the whole page's brand color.
   --af-heading/--af-text/--af-text-muted stay neutral dark/gray text, not
   brand color, so they're intentionally left alone.

   DESIGN SYSTEM (Production-polish pass): every radius/shadow/spacing/
   transition value on the page routes through the tokens below instead of
   being repeated as a one-off literal — border-radius, padding rhythm,
   hover/active motion and the color hierarchy (primary / hover / border /
   surface / text / secondary text / success / disabled) all read from here,
   so the whole page (cards, buttons, thumbnails, canvas, inputs) stays
   visually one system instead of drifting component-by-component.
   ===================================================================== */

.af-wrap {
  --af-primary: #1c48c1;
  --af-primary-dark: #163a99;
  --af-primary-hover: var(--af-primary-dark);
  --af-primary-tint: #eef4ff;
  --af-accent: #1c48c1;
  --af-accent-dark: #163a99;
  --af-accent-rgb: 28, 72, 193;
  --af-bg: #fffcf5;
  --af-heading: #212d40;
  --af-text: #5e6282;
  --af-text-muted: #90969f;
  --af-velamart-primary: #1c48c1;
  --af-velamart-primary-dark: #163a99;

  /* Color hierarchy tokens (item 10) — same hex values already in use
     throughout the page, just centralized instead of repeated literals. */
  --af-border: #e2e8f0;
  --af-border-light: #eef1f6;
  --af-surface: #fff;
  --af-surface-muted: #f8fafc;
  --af-success: #16a34a;
  --af-disabled-opacity: .5;

  /* Spacing rhythm (item 9) */
  --af-space-2xs: 4px;
  --af-space-xs: 8px;
  --af-space-sm: 12px;
  --af-space-md: 16px;
  --af-space-lg: 24px;

  /* Radius scale — sm for small controls (tabs/badges/toolbar buttons), md
     for input-like cards (size choice, download CTA), lg for panels, xl for
     the focal canvas/preview squares so they read as the star of the page
     (item 4: "Canvas nổi bật hơn"). */
  --af-radius-sm: 8px;
  --af-radius-md: 12px;
  --af-radius-lg: 16px;
  --af-radius-xl: 20px;
  --af-radius-full: 999px;

  /* Shadow scale — all "rất nhẹ" (very soft), never a hard drop shadow. */
  --af-shadow-sm: 0 2px 8px rgba(15, 23, 42, .06);
  --af-shadow-md: 0 8px 24px rgba(15, 23, 42, .08);
  --af-shadow-lg: 0 14px 34px rgba(15, 23, 42, .12);

  /* Motion — one timing/easing pair reused everywhere (item 11: 0.2-0.25s,
     "không gây rối mắt" = state-change transitions only, no auto-playing
     keyframe animation). -fast is for hover "lift" transforms, which read
     better a little snappier than color/background fades. */
  --af-ease: cubic-bezier(.4, 0, .2, 1);
  --af-transition: .22s var(--af-ease);
  --af-transition-fast: .15s var(--af-ease);

  max-width: 1800px;
  margin: 0 auto;
  padding: 6px 28px 60px;
  background: var(--af-bg);
  font-family: 'Google Sans Text', Roboto, Arial, sans-serif;
}

.af-wrap .af-hero-title,
.af-wrap .af-panel-title,
.af-wrap .af-guide-title,
.af-wrap .af-size-main,
.af-wrap .af-guide-step h3,
.af-wrap .af-founder-name {
  font-family: 'Google Sans', Roboto, Arial, sans-serif;
}

/* ---------------------------------------------------------------------
   HEADER (hero) + STEP INDICATOR
   Compact, single-purpose header: title, one-line description, and a
   slim stepper — not a full marketing hero — so the fold reaches the
   actual tool (Left/Center/Right cards) much sooner. Height + margins
   trimmed ~45% versus the previous pass to hand that space back to the
   working area, per "tăng thêm không gian cho vùng thao tác".
   --------------------------------------------------------------------- */
.af-hero {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--af-space-lg);
  margin-bottom: 6px;
  flex-wrap: wrap;
}

.af-hero-text {
  text-align: left;
}

.af-hero-title {
  font-size: 20px;
  font-weight: 700;
  line-height: 1.25;
  color: var(--af-heading);
  /* Tight title->description gap (was 8px). */
  margin: 0 0 3px;
}

.af-hero-title .af-brand {
  color: var(--af-primary);
}

.af-hero-desc {
  color: var(--af-text);
  font-size: 12px;
  font-weight: 400;
  line-height: 1.4;
  margin: 0;
}

.af-steps {
  display: flex;
  /* flex-start (not center): each step column's own height varies slightly
     by label text width/wrap, so centering the row would make the connector
     line drift off the circles' true center. Anchoring every child to the
     row's top and giving the line an explicit margin-top (below) keeps the
     line locked to the circle's center regardless of label height —
     "khoảng cách đều, căn giữa đẹp hơn" without fragile magic-number tuning. */
  align-items: flex-start;
  justify-content: center;
  gap: var(--af-space-xs);
  flex-shrink: 0;
}

.af-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  min-width: 64px;
}

.af-step-num {
  width: 26px;
  height: 26px;
  border-radius: var(--af-radius-full);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11.5px;
  font-weight: 700;
  /* Inactive: softer than before (was #e2e8f0/text-muted on a heavier
     weight) — "trạng thái Inactive dịu hơn". */
  background: var(--af-border-light);
  color: var(--af-text-muted);
  box-sizing: border-box;
  transition: background var(--af-transition), color var(--af-transition), box-shadow var(--af-transition);
}

.af-step.is-active .af-step-num {
  background: var(--af-primary);
  color: #fff;
  /* Soft halo instead of a harder box-shadow — "trạng thái Active nổi
     bật" without a heavy drop shadow. */
  box-shadow: 0 0 0 4px rgba(var(--af-accent-rgb), .14);
}

.af-step-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--af-text-muted);
  white-space: nowrap;
  transition: color var(--af-transition);
}

.af-step.is-active .af-step-label {
  color: var(--af-primary);
  font-weight: 700;
}

.af-step-line {
  width: 36px;
  height: 1.5px;
  /* Centers on the 26px circle above: (26 - 1.5) / 2. */
  margin-top: 12.25px;
  background: var(--af-border-light);
  border-radius: var(--af-radius-full);
  transition: background var(--af-transition);
}

.af-step-line.is-active {
  /* Solid primary (was a gradient) — cleaner "completed" read at this
     smaller thinner scale. */
  background: var(--af-primary);
}

/* ---------------------------------------------------------------------
   MAIN TOOL GRID — full-width editor layout, not an article container.
   Base (this rule, unscoped) = tablet "2 panel" shape: Left+Center stacked
   in column 1, Right spans both rows in column 2. Desktop (>=1280px)
   below switches to the true 3-panel 22/53/25 row. Mobile (<768px, further
   down) collapses everything to a single column.
   --------------------------------------------------------------------- */
.af-grid3 {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: var(--af-space-lg);
  /* stretch (grid default): all panels in a row equal the height of the
     tallest one — Left/Center/Right must always match. Panels that would
     otherwise be shorter (e.g. Left's frame list) fill the extra height
     instead of leaving a gap; panels whose own content is longer than
     that shared height scroll internally instead of growing the row
     further (see .af-frame-picker's flex:1/min-height:0 below). */
  align-items: stretch;
}

.af-panel-left   { grid-column: 1; grid-row: 1; display: flex; flex-direction: column; }
.af-panel-center { grid-column: 1; grid-row: 2; }
.af-panel-right  { grid-column: 2; grid-row: 1 / span 2; }

/* The pinned 3-column desktop shape genuinely needs room (Left/Right have
   real px minimums) — kept media-gated, but at 1024px instead of 1280px so
   a merely-not-maximized browser window still gets it instead of silently
   falling back to the 2-panel tablet shape. */
@media (min-width: 1024px) {
  .af-grid3 {
    /* Canvas panel grown ~10-15% ("Tăng kích thước vùng canvas") — Grid only
       hands a track extra space *after* smaller-capacity tracks are filled
       to their own max first, so simply raising Center's max (520px) alone
       only paid off once the viewport was wide enough that Left+Right had
       already maxed out AND there was still leftover (~1474px+); at 1366px
       Center was still landing on the exact same width as before. Trimming
       Left/Right's max ceiling slightly (390->375, 460->430 — their min,
       i.e. actual usable floor, is untouched) frees that room for Center at
       every desktop width, not just very wide ones. */
    grid-template-columns: minmax(350px, 375px) minmax(0, 520px) minmax(420px, 430px);
    justify-content: center;
  }

  .af-panel-left   { grid-column: 1; grid-row: auto; }
  .af-panel-center { grid-column: 2; grid-row: auto; }
  .af-panel-right  { grid-column: 3; grid-row: auto; }
}

.af-panel {
  background: var(--af-surface);
  border-radius: var(--af-radius-lg);
  box-shadow: var(--af-shadow-md);
  border: 1px solid var(--af-border-light);
  padding: var(--af-space-lg);
  min-width: 0; /* prevent grid "blowout": replaced elements (canvas/img) inside
                   would otherwise force this track wider than the viewport. */
  /* Equal-height cards: stretch (from .af-grid3/.af-grid-bottom's grid
     align-items) gives every panel in a row the same height; flex column +
     min-height:0 here is what lets an inner list (e.g. .af-frame-picker)
     size itself against that shared height and scroll instead of forcing
     the row taller. Height is always relative to siblings, never a fixed px. */
  height: 100%;
  min-height: 0;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  transition: box-shadow var(--af-transition);
}

.af-panel-title {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .02em;
  color: var(--af-heading);
  margin: 0 0 var(--af-space-md);
}

/* ---------------------------------------------------------------------
   LEFT PANEL — frame tabs + grid + "xem thêm"
   (Shared with the mobile FAB/bottom-sheet: on desktop/tablet the sheet
   chrome collapses to a plain static block via the baseline rules below;
   the mobile media query turns the SAME markup into a slide-up sheet.)
   --------------------------------------------------------------------- */
.af-frame-sheet-backdrop,
.af-frame-sheet-handle {
  display: none;
}

#af-frame-sheet {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.af-frame-sheet-panel {
  position: static;
  transform: none;
  background: transparent;
  box-shadow: none;
  padding: 0;
  max-height: none;
  overflow: visible;
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.af-tabs {
  display: flex;
  gap: 4px;
  margin-bottom: var(--af-space-md);
  flex-wrap: nowrap;
  justify-content: space-between;
}

.af-tab {
  /* Fixed height (not min-height) so all 4 tabs share the exact same box —
     "đồng bộ kích thước" — regardless of label length. */
  flex: 1 1 0;
  height: 34px;
  min-width: 0;
  border: 1.5px solid transparent;
  background: none;
  border-radius: var(--af-radius-sm);
  padding: 0 6px;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--af-text);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background var(--af-transition), border-color var(--af-transition), color var(--af-transition);
}

.af-tab:hover:not(:disabled):not(.is-active) {
  border-color: var(--af-border);
  background: var(--af-surface-muted);
  color: var(--af-heading);
}

.af-tab.is-active {
  border-color: var(--af-primary);
  background: var(--af-primary-tint);
  color: var(--af-primary);
}

.af-tab:disabled {
  cursor: not-allowed;
  opacity: .55;
}

.af-frame-picker {
  display: grid;
  /* Fluid to the panel's own width (was a fixed 120px pinned column, which
     left a large centered gutter on wider Left panels) — thumbnails now
     scale with the card so the image fills it properly instead of floating
     in unused white space. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--af-space-xs);
  /* Default (tablet/mobile-static/base): Left panel here is *not* sharing a
     grid row with Center (see the tablet 2-panel shape below), so there is
     no external height for a flex-grow item to fill — natural height capped
     with a scroll fallback, same as the picker always behaved pre-equal-
     height-cards. min-height:auto (the flex/grid default) matters here: it
     is what makes this track's row size to the picker's real content. */
  overflow-y: auto;
  max-height: 60vh;
  padding-right: 4px;
}

@media (min-width: 1024px) {
  .af-frame-picker {
    /* Desktop 3-column shape: Left *does* share its row with Center (whose
       square canvas gives the row a real, external height), so flex:1 can
       fill whatever's left after the title/tabs/"xem thêm" button — not a
       fixed px cap — and scroll internally only if the frame list is still
       taller than that. min-height:0 is required so this flex item can
       shrink below its content size instead of forcing the panel/row
       taller. Trying to use this same flex:1/min-height:0 combination in
       the tablet shape above is exactly what collapses the picker to 0px:
       flex-grow has nothing to grow into when the row's own height is
       itself derived from this item's content (no Center in the row to
       anchor it), so it degenerates to its min-height instead — hence
       gating it to only the layout where Center actually anchors the row.
       "safe center" means a short frame list (fewer rows than the
       available height) sits centered in that space instead of pinned to
       the top with dead space below it; "safe" matters once the list is
       long enough to scroll — plain center would center the *overflow*
       too, clipping the first row above the fold until the user scrolls
       up. "safe" falls back to start-alignment in that case so row 1 is
       always visible on load. */
    flex: 1 1 0;
    min-height: 0;
    max-height: none;
    align-content: safe center;
  }
}

.af-frame-picker.is-expanded {
  /* "Xem thêm khung" — grow to show every frame with no internal scroll,
     same as before; this now simply opts out of the flex:1 cap above. */
  flex: none;
  max-height: none;
  overflow: visible;
}

.af-frame-thumb {
  position: relative;
  border: 2px solid transparent;
  border-radius: var(--af-radius-md);
  /* % padding (not px) so the image always fills ~90% of the thumb
     regardless of how wide the fluid grid column ends up — percentage
     padding resolves against the box's own width on every side, which
     keeps a square inset on a square (1:1) box at any size. */
  padding: 4%;
  cursor: pointer;
  background: var(--af-surface-muted);
  box-sizing: border-box;
  transition: border-color var(--af-transition), box-shadow var(--af-transition), transform var(--af-transition-fast);
}

.af-frame-thumb:hover {
  /* "scale nhẹ, shadow nhẹ" */
  transform: translateY(-2px) scale(1.02);
  box-shadow: var(--af-shadow-sm);
}

.af-frame-thumb img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: contain;
  display: block;
  margin: 0 auto;
  border-radius: var(--af-radius-sm);
}

.af-frame-thumb.is-selected {
  border-color: var(--af-primary);
  /* Ring + lift instead of a single flat border — "border đẹp hơn". */
  box-shadow: 0 0 0 3px rgba(var(--af-accent-rgb), .14), var(--af-shadow-sm);
}

.af-frame-thumb.is-selected:hover {
  transform: none; /* already visually "selected" — don't also lift on hover */
}

.af-frame-thumb.is-selected::after {
  content: "✓";
  position: absolute;
  top: 6px;
  left: 6px;
  width: 20px;
  height: 20px;
  border-radius: var(--af-radius-full);
  background: var(--af-primary);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  box-shadow: 0 2px 6px rgba(var(--af-accent-rgb), .35);
  box-sizing: border-box;
}

.af-frame-more {
  width: 100%;
  margin-top: var(--af-space-md);
  padding: var(--af-space-xs);
  border: 1px solid var(--af-border);
  border-radius: var(--af-radius-sm);
  background: var(--af-surface-muted);
  color: var(--af-text);
  font-weight: 600;
  font-size: 13px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  cursor: pointer;
  transition: background var(--af-transition), border-color var(--af-transition), transform var(--af-transition-fast);
}

.af-frame-more:hover {
  background: #f1f5f9;
  border-color: #d7dee8;
}

.af-frame-more:active {
  transform: scale(.98);
}

.af-frame-more.is-expanded svg {
  transform: rotate(180deg);
  transition: transform var(--af-transition);
}

/* "Chọn khung ▼" trigger — Desktop/Tablet already show the frame picker
   inline in this card, so the trigger stays hidden there (only styled/
   shown inside the <768px mobile query below). Also fixes a pre-existing
   bug: with no base display rule at all, this <button> fell back to the
   browser default (inline-block) and rendered as a small unstyled stray
   button under the canvas on Desktop/Tablet. */
.af-frame-fab {
  display: none;
}

/* ---------------------------------------------------------------------
   CENTER PANEL — toolbar, canvas stage, zoom row
   This is the focal panel of the page (item 4: "vùng quan trọng nhất") —
   biggest canvas, most rounded corners, closest-fit chrome around it.
   --------------------------------------------------------------------- */
.af-panel-center {
  display: flex;
  flex-direction: column;
  /* Toolbar + canvas + zoom row are a fixed-height block (canvas is square,
     doesn't grow to fill); when the equal-height row (see .af-grid3) makes
     this card taller than that block, center it instead of leaving all the
     slack as dead space under the zoom row. */
  justify-content: center;
}

.af-toolbar {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: center;
  gap: var(--af-space-xs);
  height: 40px;
  margin-bottom: var(--af-space-sm);
  /* Safety net, not the primary fix: Left/Right panel widths + button count
     can push natural content past the Canvas panel's width. Scrolling here
     (instead of the row overflowing the panel) is what stops the toolbar
     from ever visually bleeding into the Preview panel next to it. */
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.af-toolbar::-webkit-scrollbar {
  display: none;
}

.af-toolbar-tools {
  display: flex;
  align-items: center;
  gap: var(--af-space-xs);
  flex-shrink: 0;
}

/* Every toolbar button — Upload + the 4 edit tools + Reset — is the exact
   same 40x40 icon square ("các nút cùng kích thước, icon căn giữa, khoảng
   cách đều"). Icon-only (labels hidden below) + a native title="" tooltip
   is what guarantees the row never needs to truncate text or wrap — "Nếu
   thiếu chiều ngang thì responsive hợp lý. Không để text bị cắt." — while
   staying compact enough that Upload/Zoom/Rotate/Reset always fit in one
   row on desktop and tablet. Mobile restores the original icon+label pill
   row further down (its own dedicated scrollable layout). */
.af-tool-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  gap: 0;
  border: 1px solid var(--af-border);
  border-radius: var(--af-radius-sm);
  background: var(--af-surface-muted);
  cursor: pointer;
  font-size: 12px;
  font-weight: 600;
  color: var(--af-text);
  position: relative;
  flex-shrink: 0;
  box-sizing: border-box;
  white-space: nowrap;
  transition: background var(--af-transition), border-color var(--af-transition),
    color var(--af-transition), box-shadow var(--af-transition),
    transform var(--af-transition-fast);
}

.af-tool-btn:hover {
  background: #f1f5f9;
  border-color: #d7dee8;
  color: var(--af-velamart-primary);
  transform: translateY(-1px);
  box-shadow: var(--af-shadow-sm);
}

.af-tool-btn:active {
  transform: translateY(0) scale(.94);
  box-shadow: none;
}

.af-toolbar .af-tool-btn span {
  display: none;
}

/* "Tải ảnh" — the Primary Button (filled); the 5 tools next to it are
   Secondary Buttons (outlined, from the shared .af-tool-btn rule above). */
.af-tool-btn--primary {
  background: var(--af-velamart-primary);
  border-color: var(--af-velamart-primary);
  color: #fff;
}

.af-tool-btn--primary:hover {
  background: var(--af-primary-hover);
  border-color: var(--af-primary-hover);
  color: #fff;
}

.af-tool-btn svg {
  transition: none;
}

.af-tool-btn input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.af-canvas-wrap {
  position: relative;
  width: 100%;
}

.af-stage {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  margin: 0 auto;
  /* Slightly softer checker + lighter overall so the frame/photo the user
     is editing reads as the brightest thing in the card — "background
     sáng nhẹ" — while still clearly signaling transparency. */
  background: repeating-conic-gradient(#f8fafc 0% 25%, #eef1f6 0% 50%) 50% / 20px 20px;
  border: 1px solid var(--af-border-light);
  /* Biggest radius on the page — the canvas is the focal element
     ("Canvas nổi bật hơn"). */
  border-radius: var(--af-radius-xl);
  box-shadow: var(--af-shadow-md);
  overflow: hidden;
  transition: box-shadow var(--af-transition);
}

.af-stage-empty {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-align: center;
  color: var(--af-text-muted);
  font-size: 13px;
  padding: 24px;
}

.af-stage.is-active .af-stage-empty {
  display: none;
}

.af-editor {
  position: absolute;
  inset: 0;
  visibility: hidden;
  opacity: 0;
  /* Fade-in once a photo loads (JS only ever toggles .is-active — this is
     a purely presentational transition on that same existing state, not a
     new behavior). */
  transition: opacity var(--af-transition);
}

.af-stage.is-active .af-editor {
  visibility: visible;
  opacity: 1;
}

.af-editor img {
  max-width: 100%;
  display: block;
}

.af-frame-overlay {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  pointer-events: none;
  z-index: 10;
}

/* Cropper.js's own chrome (vendor/cropper.min.css) draws a permanent blue
   outline around .cropper-view-box — the crop viewport window — regardless
   of the guides/center/highlight/cropBoxResizable/cropBoxMovable options
   already set in avatar-frame.js. Where a circular/thin frame artwork
   doesn't fully cover that square viewport's edge (most visibly the top),
   this 1px outline shows through as a stray blue line inside the photo that
   has nothing to do with any frame image. Neutralized here (never edit the
   vendor file) — outline is purely decorative, not part of the
   overflow:hidden clipping that actually crops the image, so this has zero
   effect on upload/crop/zoom/rotate/drag/download behavior. .cropper-face/
   .cropper-line/.cropper-point (selection highlight, resize handles) are
   already fully suppressed by the existing highlight:false/
   cropBoxResizable:false options — verified via DOM inspection, no CSS
   override needed for those. */
.af-stage .cropper-view-box {
  outline: none;
}

.af-zoom-row {
  display: flex;
  align-items: center;
  gap: 10px;
  /* Sit snug under the canvas ("nằm sát canvas"), not the same 16px rhythm
     used for unrelated title/section gaps elsewhere in the card. */
  margin-top: var(--af-space-sm);
}

.af-zoom-step {
  width: 28px;
  height: 28px;
  border-radius: var(--af-radius-full);
  border: 1px solid var(--af-border);
  background: var(--af-surface);
  color: var(--af-text);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
  box-sizing: border-box;
  transition: background var(--af-transition), border-color var(--af-transition), transform var(--af-transition-fast);
}

.af-zoom-step:hover {
  background: #f1f5f9;
  border-color: #d7dee8;
}

.af-zoom-step:active {
  transform: scale(.92);
}

.af-zoom-slider {
  flex: 1;
  -webkit-appearance: none;
  appearance: none;
  height: 4px;
  border-radius: var(--af-radius-full);
  background: var(--af-border);
  outline: none;
}

.af-zoom-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  border-radius: var(--af-radius-full);
  background: var(--af-primary);
  cursor: pointer;
  border: 2px solid #fff;
  box-shadow: 0 0 0 1px var(--af-primary);
}

.af-zoom-slider::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border-radius: var(--af-radius-full);
  background: var(--af-primary);
  cursor: pointer;
  border: 2px solid #fff;
  box-shadow: 0 0 0 1px var(--af-primary);
}

.af-zoom-value {
  font-size: 13px;
  color: var(--af-text);
  min-width: 42px;
  text-align: right;
  flex-shrink: 0;
}

/* ---------------------------------------------------------------------
   RIGHT PANEL — preview, size choice, download, checklist
   --------------------------------------------------------------------- */
.af-preview-box {
  position: relative;
  /* Bleeds past the panel's own padding on each side so the preview
     reaches ~92-95% of the card's full width (vs. ~88% at a plain 100%,
     which is only 100% of the *padded* content box) — aspect-ratio keeps
     it perfectly square either way, so this only changes how much of the
     card the square occupies, not its proportions. */
  width: calc(100% + 24px);
  margin: 0 -12px var(--af-space-sm);
  /* Upper bound only — actual rendered size is clamped by the Right panel's
     real width (see .af-grid3), so this just has to not be the limiter. */
  max-width: 460px;
  aspect-ratio: 1 / 1;
  background: repeating-conic-gradient(#f8fafc 0% 25%, #eef1f6 0% 50%) 50% / 16px 16px;
  /* Same radius/shadow language as the canvas — "Border radius đồng bộ.
     Shadow nhẹ." */
  border-radius: var(--af-radius-xl);
  box-shadow: var(--af-shadow-sm);
  overflow: hidden;
}

.af-preview-box canvas {
  width: 100%;
  height: 100%;
  display: block;
}

.af-size-choice {
  display: flex;
  gap: var(--af-space-xs);
  margin: 0 0 var(--af-space-sm);
}

.af-size-choice label {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 3px;
  border: 1.5px solid var(--af-border);
  border-radius: var(--af-radius-md);
  /* Bigger padding — "padding lớn hơn" — for a sturdier, more tappable card. */
  padding: 14px 16px;
  cursor: pointer;
  transition: border-color var(--af-transition), background var(--af-transition), box-shadow var(--af-transition);
}

.af-size-choice label:hover {
  border-color: #c7d2e0;
}

.af-size-choice label:has(input:checked) {
  border-color: var(--af-primary);
  background: var(--af-primary-tint);
  /* Clear selected state — "trạng thái Selected rõ ràng". */
  box-shadow: 0 0 0 3px rgba(var(--af-accent-rgb), .12);
}

.af-size-choice input {
  margin: 0 0 4px;
  accent-color: var(--af-primary);
}

.af-size-main {
  font-size: 13px;
  font-weight: 700;
  color: var(--af-heading);
}

.af-size-cap {
  font-size: 11px;
  color: var(--af-text-muted);
}

.af-btn-primary {
  background: var(--af-velamart-primary);
  border-color: var(--af-velamart-primary);
  color: #fff;
  transition: background var(--af-transition), box-shadow var(--af-transition), transform var(--af-transition-fast);
}

.af-btn-primary:hover {
  background: var(--af-primary-hover);
}

.af-btn-primary:disabled {
  opacity: var(--af-disabled-opacity);
  cursor: not-allowed;
}

.af-download-btn {
  width: 100%;
  /* CTA chính — "cao khoảng 50-52px" (was 48px). */
  height: 51px;
  padding: 0 12px;
  font-size: 14px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .01em;
  border-radius: var(--af-radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: none;
  cursor: pointer;
  box-sizing: border-box;
}

.af-download-btn:not(:disabled):hover {
  transform: translateY(-1px);
  box-shadow: 0 8px 20px rgba(var(--af-accent-rgb), .3);
}

.af-download-btn:not(:disabled):active {
  transform: translateY(0);
  box-shadow: none;
}

/* ---------------------------------------------------------------------
   DOWNLOAD SHEET — built dynamically by showDownloadSheet() in
   avatar-frame.js (Zalo's "Lưu ảnh/Chia sẻ/Mở bằng trình duyệt/Hủy" sheet,
   and the plain-mobile-browser 2-button fallback). Same slide-up bottom
   sheet language as .af-frame-sheet (frame picker on mobile) for visual
   consistency, but its own component since it's a modal dialog, not a
   picker, and isn't scoped to a max-width media query — Zalo/old-browser
   fallbacks are only ever mobile in practice, but nothing here assumes it.
   --------------------------------------------------------------------- */
.af-download-sheet {
  position: fixed;
  inset: 0;
  z-index: 1000;
  visibility: hidden;
  pointer-events: none;
}

.af-download-sheet.is-open {
  visibility: visible;
  pointer-events: auto;
}

.af-download-sheet-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(15, 23, 42, .5);
  opacity: 0;
  transition: opacity .2s ease;
}

.af-download-sheet.is-open .af-download-sheet-backdrop {
  opacity: 1;
}

.af-download-sheet-panel {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  max-width: 420px;
  margin: 0 auto;
  padding: 8px 20px calc(20px + env(safe-area-inset-bottom));
  background: var(--af-surface);
  border-radius: var(--af-radius-lg) var(--af-radius-lg) 0 0;
  box-shadow: var(--af-shadow-lg);
  transform: translateY(100%);
  transition: transform .25s ease;
}

.af-download-sheet.is-open .af-download-sheet-panel {
  transform: translateY(0);
}

.af-download-sheet-handle {
  width: 40px;
  height: 4px;
  border-radius: var(--af-radius-full);
  background: var(--af-border);
  margin: 6px auto 14px;
  cursor: pointer;
}

.af-download-sheet-title {
  margin: 0 0 4px;
  font-size: 16px;
  font-weight: 700;
  color: var(--af-heading);
  text-align: center;
}

.af-download-sheet-desc {
  margin: 0 0 var(--af-space-md);
  font-size: 13px;
  color: var(--af-text);
  text-align: center;
}

.af-download-sheet-actions {
  display: flex;
  flex-direction: column;
  gap: var(--af-space-xs);
}

.af-download-sheet-btn {
  width: 100%;
  height: 46px;
  padding: 0 16px;
  border: 1px solid var(--af-border);
  border-radius: var(--af-radius-md);
  background: var(--af-surface-muted);
  color: var(--af-heading);
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  transition: background var(--af-transition), border-color var(--af-transition), transform var(--af-transition-fast);
}

.af-download-sheet-btn:hover {
  background: #f1f5f9;
  border-color: #d7dee8;
}

.af-download-sheet-btn:active {
  transform: scale(.98);
}

.af-download-sheet-btn--primary {
  background: var(--af-primary);
  border-color: var(--af-primary);
  color: #fff;
}

.af-download-sheet-btn--primary:hover {
  background: var(--af-primary-hover);
  border-color: var(--af-primary-hover);
}

.af-download-sheet-btn--ghost {
  background: transparent;
  border-color: transparent;
  color: var(--af-text-muted);
}

.af-download-sheet-btn--ghost:hover {
  background: var(--af-surface-muted);
  border-color: transparent;
}

.af-checklist {
  list-style: none;
  margin: var(--af-space-md) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.af-checklist li {
  display: flex;
  align-items: center;
  gap: var(--af-space-xs);
  font-size: 13px;
  color: var(--af-text);
}

.af-checklist svg {
  flex-shrink: 0;
}

/* ---------------------------------------------------------------------
   GUIDE + FAQ row — own grid (independent of .af-grid3's tablet row-span
   trick above): stacked at tablet/mobile, side-by-side (matching the
   22/53/25 rhythm) only at true desktop width.
   --------------------------------------------------------------------- */
.af-grid-bottom {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--af-space-lg);
  margin-top: var(--af-space-lg);
}

@media (min-width: 1024px) {
  .af-grid-bottom {
    /* Same column template/threshold as .af-grid3 so this row lines up under it. */
    grid-template-columns: minmax(350px, 390px) minmax(0, 460px) minmax(420px, 460px);
    justify-content: center;
  }

  .af-guide {
    grid-column: 1 / span 2;
  }

  .af-faq-card {
    grid-column: 3;
  }
}

.af-guide-title {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .02em;
  color: var(--af-heading);
  margin: 0 0 var(--af-space-md);
}

.af-guide-steps {
  display: flex;
  align-items: flex-start;
  gap: var(--af-space-md);
}

.af-guide-step {
  flex: 1;
  min-width: 0;
}

.af-guide-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: var(--af-radius-full);
  background: var(--af-primary);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  margin-bottom: var(--af-space-xs);
}

.af-guide-step h3 {
  font-size: 14px;
  font-weight: 700;
  color: var(--af-heading);
  margin: 0 0 4px;
}

.af-guide-step p {
  font-size: 12.5px;
  color: var(--af-text);
  margin: 0;
  line-height: 1.5;
}

.af-guide-arrow {
  color: #cbd5e1;
  font-size: 18px;
  padding-top: 4px;
  flex-shrink: 0;
}

/* ---- FAQ ---- */
.af-faq-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}

.af-faq-head .af-panel-title {
  margin: 0;
}

.af-faq-more {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--af-primary);
  cursor: default;
}

.af-faq-item {
  border-bottom: 1px solid var(--af-border-light);
}

.af-faq-item:last-child {
  border-bottom: none;
}

.af-faq-q {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  border: none;
  background: none;
  text-align: left;
  padding: 12px 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--af-heading);
  cursor: pointer;
}

.af-faq-icon {
  flex-shrink: 0;
  color: var(--af-text-muted);
  transition: transform var(--af-transition);
}

.af-faq-item.is-open .af-faq-icon {
  transform: rotate(180deg);
  color: var(--af-primary);
}

.af-faq-a {
  max-height: 0;
  overflow: hidden;
  transition: max-height .25s ease;
}

.af-faq-a-inner {
  padding: 0 0 14px;
  font-size: 13px;
  color: var(--af-text);
  line-height: 1.6;
}

/* ---------------------------------------------------------------------
   FOUNDER MESSAGE — static trust card (no modal/popup), between the
   Guide+FAQ row and "Có thể bạn quan tâm". Same card language as the rest
   of the page (radius/shadow/spacing tokens, Velamart primary blue for the
   avatar ring — not the admin widget's amber, to stay on this page's single
   brand color) so it reads as part of the same system, not a bolted-on ad.
   --------------------------------------------------------------------- */
.af-founder {
  margin-top: var(--af-space-lg);
}

.af-founder-card {
  display: flex;
  align-items: center;
  gap: var(--af-space-lg);
  background: var(--af-surface);
  border: 1px solid var(--af-border-light);
  border-radius: var(--af-radius-lg);
  box-shadow: var(--af-shadow-sm);
  padding: 28px;
  box-sizing: border-box;
}

.af-founder-avatar-col {
  flex-shrink: 0;
}

.af-founder-avatar-ring {
  width: 112px;
  height: 112px;
  border-radius: var(--af-radius-full);
  padding: 3px;
  /* "Có viền nhận diện Velamart" — the page's one brand color, not a new one. */
  background: linear-gradient(135deg, var(--af-primary) 0%, var(--af-primary-tint) 120%);
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
}

.af-founder-avatar-ring img {
  width: 100%;
  height: 100%;
  border-radius: var(--af-radius-full);
  object-fit: cover;
  display: block;
  border: 3px solid #fff;
  box-sizing: border-box;
}

.af-founder-content {
  min-width: 0;
}

.af-founder-eyebrow {
  display: block;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--af-text-muted);
  margin-bottom: 4px;
}

.af-founder-name {
  font-size: 18px;
  font-weight: 700;
  color: var(--af-heading);
  margin: 0;
  line-height: 1.3;
}

.af-founder-title {
  display: block;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--af-primary);
  margin: 2px 0 12px;
}

.af-founder-message {
  font-size: 14px;
  line-height: 1.7;
  color: var(--af-text);
  margin: 0 0 18px;
  max-width: 62ch;
}

.af-founder-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--af-space-sm);
}

.af-founder-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 11px 20px;
  border-radius: var(--af-radius-md);
  font-size: 13.5px;
  font-weight: 700;
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
  box-sizing: border-box;
  transition: background var(--af-transition), border-color var(--af-transition),
    box-shadow var(--af-transition), transform var(--af-transition-fast), color var(--af-transition);
}

.af-founder-btn:hover {
  transform: translateY(-1px);
  text-decoration: none;
}

.af-founder-btn:active {
  transform: translateY(0);
}

/* Zalo's own brand blue — a third-party mark, not a new page accent color. */
.af-founder-btn--zalo {
  background: #0068ff;
  color: #fff;
}

.af-founder-btn--zalo:hover {
  background: #0058d6;
  color: #fff;
  box-shadow: var(--af-shadow-sm);
}

.af-founder-btn--suggest {
  background: var(--af-surface-muted);
  border-color: var(--af-border);
  color: var(--af-text);
}

.af-founder-btn--suggest:hover {
  background: #f1f5f9;
  border-color: #d7dee8;
  color: var(--af-heading);
}

/* ---------------------------------------------------------------------
   RELATED PRODUCTS
   --------------------------------------------------------------------- */
.af-related {
  margin-top: var(--af-space-lg);
}

/* ---------------------------------------------------------------------
   NỘI DUNG SEO — khối nội dung dài (Admin > Avatar Campaign > Nội dung SEO),
   hiển thị ngay dưới "Có thể bạn quan tâm". Container riêng, độc lập với
   .af-wrap (yêu cầu: Desktop max-width 1200px margin auto padding 40px /
   Mobile padding 16px) — không đụng layout/kích thước các khối khác.
   --------------------------------------------------------------------- */
.af-seo-content {
  margin-top: var(--af-space-lg);
}

.af-seo-content-inner {
  max-width: 1200px;
  margin: 0 auto;
  padding: 40px;
  box-sizing: border-box;
  background: var(--af-surface);
  border: 1px solid var(--af-border-light);
  border-radius: var(--af-radius-lg);
  box-shadow: var(--af-shadow-sm);
}

.af-seo-content-title {
  font-family: 'Google Sans', Roboto, Arial, sans-serif;
  font-size: 22px;
  font-weight: 700;
  color: var(--af-heading);
  line-height: 1.35;
  margin: 0 0 var(--af-space-md);
}

.af-seo-content-body {
  position: relative;
  max-height: 350px;
  overflow: hidden;
  font-size: 15px;
  line-height: 1.85;
  color: var(--af-text);
  transition: max-height .35s var(--af-ease);
}

.af-seo-content-body::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 72px;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0), var(--af-surface));
  pointer-events: none;
  transition: opacity .2s var(--af-ease);
}

/* max-height khi mở rộng do JS set inline (bằng đúng scrollHeight thật của nội
   dung) để animation mượt và chính xác — xem Assets/js/avatar-seo-content.js.
   Không dùng 1 hằng số lớn cố định (VD 10000px) vì tốc độ transition của
   max-height tỉ lệ với giá trị đích, sẽ làm animation bị "giật" nhanh/chậm
   tùy độ dài nội dung thật. */

.af-seo-content.is-expanded .af-seo-content-body::after,
.af-seo-content:not(.has-overflow) .af-seo-content-body::after {
  opacity: 0;
}

.af-seo-content-body h1, .af-seo-content-body h2, .af-seo-content-body h3,
.af-seo-content-body h4, .af-seo-content-body h5, .af-seo-content-body h6 {
  font-family: 'Google Sans', Roboto, Arial, sans-serif;
  color: var(--af-heading);
  font-weight: 700;
  line-height: 1.35;
  margin: 22px 0 10px;
}
.af-seo-content-body h1 { font-size: 1.6em; }
.af-seo-content-body h2 { font-size: 1.4em; }
.af-seo-content-body h3 { font-size: 1.2em; }
.af-seo-content-body h4,
.af-seo-content-body h5,
.af-seo-content-body h6 { font-size: 1.05em; }

.af-seo-content-body p { margin: 0 0 14px; }
.af-seo-content-body ul, .af-seo-content-body ol { padding-left: 24px; margin: 0 0 14px; }
.af-seo-content-body li { margin-bottom: 6px; }
.af-seo-content-body a { color: var(--af-primary); text-decoration: underline; }
.af-seo-content-body strong { font-weight: 700; color: var(--af-heading); }
.af-seo-content-body blockquote {
  border-left: 4px solid var(--af-primary);
  margin: 18px 0;
  padding: 10px 18px;
  background: var(--af-primary-tint);
  border-radius: 0 var(--af-radius-sm) var(--af-radius-sm) 0;
  color: var(--af-heading);
}
.af-seo-content-body img, .af-seo-content-body iframe {
  max-width: 100%;
  height: auto;
  border-radius: var(--af-radius-sm);
  margin: 12px 0;
}
.af-seo-content-body figure { margin: 16px 0; }
.af-seo-content-body figcaption {
  font-size: 13px;
  color: var(--af-text-muted);
  text-align: center;
  margin-top: 6px;
}
.af-seo-content-body table {
  width: 100%;
  border-collapse: collapse;
  margin: 16px 0;
  font-size: 14px;
}
.af-seo-content-body th, .af-seo-content-body td {
  border: 1px solid var(--af-border);
  padding: 8px 12px;
  text-align: left;
}
.af-seo-content-body th { background: var(--af-surface-muted); font-weight: 600; }
.af-seo-content-body pre {
  background: #1e293b;
  color: #e2e8f0;
  padding: 14px 18px;
  border-radius: var(--af-radius-sm);
  overflow-x: auto;
  font-size: 13px;
}
.af-seo-content-body code {
  background: var(--af-surface-muted);
  padding: 2px 6px;
  border-radius: 4px;
  font-size: .9em;
}

.af-seo-content-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: var(--af-space-md) auto 0;
  padding: 9px 20px;
  background: var(--af-surface);
  border: 1.5px solid var(--af-primary);
  border-radius: var(--af-radius-full);
  color: var(--af-primary);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--af-transition-fast), color var(--af-transition-fast);
}
.af-seo-content-toggle:hover {
  background: var(--af-primary-tint);
}
.af-seo-content-toggle svg {
  transition: transform .3s var(--af-ease);
}
.af-seo-content.is-expanded .af-seo-content-toggle svg {
  transform: rotate(180deg);
}

@media (max-width: 767px) {
  .af-seo-content-inner {
    padding: 16px;
    border-radius: var(--af-radius-md);
  }
  .af-seo-content-title {
    font-size: 18px;
  }
  .af-seo-content-body {
    font-size: 14px;
    line-height: 1.75;
  }
}

/* ===================================================================
   Mobile (<768px) — dedicated layout, not just a shrunk desktop view.
   =================================================================== */
@media (max-width: 767px) {
  .af-wrap {
    padding: calc(14px + env(safe-area-inset-top)) 12px calc(96px + env(safe-area-inset-bottom));
  }

  .af-hero {
    flex-direction: column;
    gap: var(--af-space-sm);
    margin-bottom: var(--af-space-md);
  }

  .af-hero-title {
    font-size: 19px;
  }

  .af-steps {
    padding-top: 0;
  }

  /* Stepper shrunk ~20% versus Desktop/Tablet to free up more room for the
     working area on small screens. */
  .af-step {
    gap: 4px;
    min-width: 51px;
  }

  .af-step-num {
    width: 21px;
    height: 21px;
    font-size: 9px;
  }

  .af-step-label {
    font-size: 9px;
  }

  .af-step-line {
    width: 29px;
    /* Centers on the 21px circle above: (21 - 1.5) / 2. */
    margin-top: 9.75px;
  }

  .af-grid3,
  .af-grid-bottom {
    grid-template-columns: 1fr;
    gap: 18px;
  }

  .af-panel-left,
  .af-panel-center,
  .af-panel-right {
    grid-column: 1;
    grid-row: auto;
  }

  .af-panel {
    padding: 14px;
  }

  /* Left panel: card shell (bg/border/shadow) collapses on mobile — the
     ONLY thing shown here now is the always-visible "Chọn khung ▼" trigger
     button; the frame list itself lives in #af-frame-sheet, which becomes
     a slide-up bottom sheet (position:fixed, removed from flow) further
     below. Previously this panel had NO visible child at all before a
     photo was uploaded (the old FAB lived inside the canvas and only
     appeared once .is-active) — Step 1 "Chọn khung" was completely
     unreachable. Fixed by moving the trigger here and making it permanent. */
  .af-panel-left {
    padding: 0;
    border: none;
    box-shadow: none;
    background: transparent;
  }

  /* ---- "Chọn khung ▼" trigger — always visible, opens the same bottom
     sheet as before via the unchanged #af-frame-fab click listener in
     avatar-frame.js (openFrameSheet()); no upload/crop/frame-apply logic
     touched, this only controls whether the picker UI is reachable. ---- */
  .af-frame-fab {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    height: 46px;
    margin-bottom: 14px;
    padding: 0 16px;
    border-radius: var(--af-radius-md);
    border: 1.5px solid var(--af-primary);
    background: var(--af-primary-tint);
    color: var(--af-primary);
    font-size: 14px;
    font-weight: 700;
    box-sizing: border-box;
    cursor: pointer;
    transition: background var(--af-transition), transform var(--af-transition-fast);
  }

  .af-frame-fab-icon {
    font-size: 17px;
    line-height: 1;
  }

  .af-frame-fab-chevron {
    flex-shrink: 0;
  }

  .af-frame-fab:active {
    transform: scale(.98);
    background: #dde9fc;
  }

  /* ---- Canvas as the centerpiece — full available width (was capped at
     min(380px,100%), leaving unused side space on wider phones like
     390-430px viewports). ---- */
  .af-canvas-wrap {
    margin: 0 0 18px;
  }

  .af-stage {
    max-width: 100%;
    margin: 0 auto;
  }

  /* ---- Toolbar: the 5 edit tools (Zoom/Xoay/Reset) stay the compact
     icon-only squares used on Desktop/Tablet; "Tải ảnh" — the primary CTA —
     gets its label back plus a bigger, more tappable pill so it visibly
     reads as the main action, not just one more icon in the row. Sized so
     all 6 buttons still fit one line with no scroll at 390px (verified). */
  .af-toolbar {
    justify-content: center;
    gap: 8px;
    height: 44px;
  }

  .af-tool-btn {
    width: 36px;
    height: 36px;
  }

  .af-tool-btn:hover {
    transform: none;
    box-shadow: none;
  }

  .af-tool-btn:active {
    transform: scale(.94);
  }

  .af-toolbar .af-tool-btn--primary span {
    display: inline;
  }

  .af-tool-btn--primary {
    width: auto;
    height: 42px;
    padding: 0 12px;
    gap: 8px;
    border-radius: 11px;
    font-size: 14px;
    font-weight: 700;
  }

  .af-tool-btn--primary svg {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
  }

  /* ---- Frame picker becomes a Bottom Sheet ---- */
  .af-frame-sheet {
    position: fixed;
    inset: 0;
    z-index: 1000;
    visibility: hidden;
    pointer-events: none;
  }

  .af-frame-sheet.is-open {
    visibility: visible;
    pointer-events: auto;
  }

  .af-frame-sheet-backdrop {
    display: block;
    position: absolute;
    inset: 0;
    background: rgba(15, 23, 42, .5);
    opacity: 0;
    transition: opacity .2s ease;
  }

  .af-frame-sheet.is-open .af-frame-sheet-backdrop {
    opacity: 1;
  }

  .af-frame-sheet-panel {
    display: block;
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    max-height: 78vh;
    overflow-y: auto;
    background: #fff;
    border-radius: 16px 16px 0 0;
    padding: 8px 16px calc(16px + env(safe-area-inset-bottom));
    box-shadow: 0 -8px 24px rgba(0, 0, 0, .15);
    transform: translateY(100%);
    transition: transform .25s ease;
  }

  .af-frame-sheet.is-open .af-frame-sheet-panel {
    transform: translateY(0);
  }

  .af-frame-sheet-handle {
    display: block;
    width: 40px;
    height: 4px;
    border-radius: 2px;
    background: #cbd5e1;
    margin: 6px auto 10px;
    cursor: pointer;
  }

  .af-frame-thumb:hover {
    transform: none;
    box-shadow: none;
  }

  .af-frame-thumb:active {
    transform: scale(.96);
  }

  /* ---- Right panel: "Xem trước" box hidden on Mobile ----
     The editing Canvas (#af-stage) already shows the photo with the frame
     overlaid live (#af-frame-overlay sits on top of it via CSS, updated on
     every drag/zoom/rotate) — it IS a real-time preview, and it's also the
     only one of the two that's actually interactive (Cropper.js drag/zoom
     lives there; this preview box is a passive canvas snapshot). Showing
     both stacked on a phone was two near-identical squares eating the whole
     screen for no benefit, so only the interactive one stays visible here;
     Desktop/Tablet keep both exactly as before (unscoped rules untouched).
     Pure display change — schedulePreview()/drawComposite() still run
     every frame in JS (harmless on a hidden canvas) and the full-res
     download render is a fully separate, independent code path, so both
     the small preview canvas and Download stay 100% functionally intact
     even though this box isn't shown. */
  .af-panel-right > .af-panel-title,
  .af-preview-box {
    display: none;
  }

  /* ---- Download: always visible, full-width sticky bar, safe-area aware ---- */
  #af-download-btn.af-download-btn {
    position: fixed;
    left: 16px;
    right: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom));
    width: auto;
    height: 54px;
    margin: 0;
    box-shadow: 0 6px 20px rgba(var(--af-accent-rgb), .35);
    z-index: 900;
  }

  #af-download-btn.af-download-btn:not(:disabled):hover {
    transform: none;
  }

  .af-wrap {
    padding-bottom: calc(96px + env(safe-area-inset-bottom));
  }

  /* ---- Guide steps stack vertically on mobile ---- */
  .af-guide-steps {
    flex-direction: column;
    gap: var(--af-space-md);
  }

  .af-guide-arrow {
    display: none;
  }

  /* "Mobile: 1 cột" — avatar centered on top, text/CTA stacked below,
     full-width buttons so they stay easy to tap. */
  .af-founder-card {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--af-space-sm);
    padding: 20px;
  }

  .af-founder-avatar-ring {
    width: 88px;
    height: 88px;
  }

  .af-founder-message {
    max-width: none;
  }

  .af-founder-actions {
    width: 100%;
    justify-content: center;
  }

  .af-founder-btn {
    flex: 1 1 auto;
    justify-content: center;
  }
}

/* ===================================================================
   Tablet (768px–1279px) — "2 panel" layout: the unscoped .af-grid3/
   .af-grid-bottom rules above already provide this shape by default
   (only the desktop >=1280px query and the mobile <768px query override
   them), so this block is just a padding touch-up.
   =================================================================== */
@media (min-width: 768px) and (max-width: 1279px) {
  .af-wrap {
    padding-left: 24px;
    padding-right: 24px;
  }

  .af-panel {
    padding: 18px;
  }

  /* "Tablet: 2 cột thu gọn" — same 2-column row as desktop, just a smaller
     avatar and tighter padding so it doesn't dominate the narrower width. */
  .af-founder-card {
    gap: var(--af-space-md);
    padding: 22px;
  }

  .af-founder-avatar-ring {
    width: 88px;
    height: 88px;
  }
}

/* Same "Tải ảnh" primary-CTA treatment as Mobile — Tablet's Center column
   can be just as narrow as a phone viewport in the 2-panel shape (e.g.
   ~340px of usable toolbar width at 768px), so it needs the same care.
   Deliberately its own (min-width:768px)/(max-width:1023px) query, NOT
   folded into the 768-1279px block above: that block's range overlaps the
   >=1024px Desktop 3-column shape too (both apply at once there, cascading
   by source order), and Desktop must stay untouched — 1024px is exactly
   where .af-grid3 already switches away from this 2-panel shape. */
@media (min-width: 768px) and (max-width: 1023px) {
  .af-toolbar {
    justify-content: center;
    gap: 8px;
    height: 44px;
  }

  .af-tool-btn {
    width: 36px;
    height: 36px;
  }

  .af-toolbar .af-tool-btn--primary span {
    display: inline;
  }

  .af-tool-btn--primary {
    width: auto;
    height: 42px;
    padding: 0 12px;
    gap: 8px;
    border-radius: 11px;
    font-size: 14px;
    font-weight: 700;
  }

  .af-tool-btn--primary svg {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
  }
}
