/* The Griptok designer (/griptok/ (live; /preview/griptok/ keeps its own copy)), on top of shop.css: only what the new elements need --
   the stage's view switch and its watermark, the row menu, the generate button and its progress, the
   outcome card with the drawn picture and the spelling check, the confirm sheet's letters, the "not
   open now" state. Everything
   else (header, tabs, stage card, cards, swatches, sheets, toast) is shop.css as on the keychain and
   pencil pages (the three-tab row on a narrow phone included). The waiting animation's own look is
   griptok-wait.css, loaded after this file: here only the boxes it draws in. ?motion=0 is shop.css's
   .nomotion rule; prefers-reduced-motion is handled below. */

.hero .nw{white-space:nowrap}

/* ---------- stage ---------- */
#window griptok-stage{position:absolute;inset:0;display:block}
/* the blank disc's caption, in the drag hint's place until there is a design to drag round */
#stageEmpty{inset:auto 8px 2px;display:flex;justify-content:center}
#stageEmpty span{max-width:100%;padding:6px 12px;border-radius:999px;background:#ffffffd9;box-shadow:0 0 0 1px #0f172a1f;
  font-size:11px;color:var(--ink2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#stageEmpty:not([hidden]) ~ #hint:not([data-failed]){visibility:hidden}
/* once the stage has been dragged the hint goes: it would only sit on the emblem */
#hint.used:not([data-failed]){opacity:0;transition:opacity .4s}
/* while a design is on its way: griptok-wait.js draws over the disc in #waitFx; drags still reach the stage */
#waitFx{position:absolute;z-index:3;inset:0;pointer-events:none}
/* without that script, the stage washes out under one calm line instead (the time is in the card) */
#busyFx{position:absolute;z-index:3;inset:0;display:grid;place-items:center;background:#eef1f6b8;pointer-events:none;
  animation:gtfade .25s ease}
#busyFx span{display:flex;align-items:center;gap:8px;padding:9px 16px;border-radius:999px;background:#fff;
  box-shadow:0 0 0 1px #0f172a14,0 10px 24px -12px #0f172a59;font-size:13px;font-weight:600;color:var(--ink2)}
#busyFx i{width:8px;height:8px;flex:none;border-radius:50%;background:var(--blue);animation:gtpulse 1.1s ease-in-out infinite}
#busyFx em{font-style:normal}
/* either way the drag hint steps aside: it would sit on the letters */
#waitFx:not([hidden]) ~ #hint:not([data-failed]),#busyFx:not([hidden]) ~ #hint:not([data-failed]){visibility:hidden}
/* บน Griptok / เฉพาะชิ้นงาน, under the stage where the keychain pages show the ship-out date */
.viewbar{display:flex;justify-content:center;padding:6px 12px;border-top:1px solid #0f172a0f}
.viewbar .pill button{min-height:34px;padding:0 14px}

/* ---------- the product switch: Griptok (แบบปกติ / MagSafe) or keychain ---------- */
#productCard{gap:10px}
.gtkind{display:flex;justify-content:center}
.gtkind[hidden]{display:none}
.gtkind .pill button{min-width:96px}
.gtprod{margin:0;padding:0 2px;font-size:12px;line-height:1.5;color:var(--ink3);text-align:center}

/* ---------- name card: the field, the generate button, its progress and its notes ---------- */
#nameCard #txt{flex:none}
.gthelp{margin:-4px 2px 0;font-size:12px;line-height:1.55;color:var(--ink4)}
.gtgo{min-height:52px;padding:0 14px;border:0;border-radius:13px;background:var(--blue);color:var(--on-accent);
  font-size:15px;font-weight:700;display:flex;align-items:center;justify-content:center;gap:8px;
  transition:background .15s,transform .1s}
.gtgo:hover:not(:disabled){background:var(--blue-d)}
.gtgo:active:not(:disabled){transform:scale(.985)}
.gtgo:disabled{background:#e2e8f0;color:var(--ink4)}
.gtgo[aria-busy="true"]:disabled{background:#bbf7d0;color:var(--green-ink)}
.gtghost{min-height:52px;border-radius:13px;border:1px solid #0f172a1f;background:#fff;color:var(--ink2);font-size:14px;font-weight:700}
.gtghost:hover{background:#0f172a0a}
.gtghost.wide{display:block;width:100%;min-height:46px;margin-top:12px}

/* progress: the bar reaches ~90% at the usual 15 s and then only creeps, so it never claims done */
#gtProg{display:flex;flex-direction:column;gap:8px;padding:2px 2px 0}
#gtProg .bar{position:relative;height:8px;border-radius:999px;background:#0f172a0f;overflow:hidden}
#gtProg .bar i{position:absolute;inset:0;border-radius:inherit;background:var(--blue);transform:scaleX(0);
  transform-origin:0 50%;transition:transform .3s linear}
#gtProg .bar::after{content:'';position:absolute;top:0;bottom:0;left:0;width:35%;
  background:linear-gradient(90deg,transparent,#ffffffa6,transparent);transform:translateX(-100%);
  animation:gtsheen 1.5s ease-in-out infinite}
/* the time keeps a line of its own: its text grows past 15 s, and the block must not grow under
   the reveal() that brought it into view */
#gtProg .ln{display:flex;flex-direction:column;gap:1px}
#progText{font-size:13px;font-weight:600;line-height:1.5;color:var(--ink2);text-wrap:pretty}
#progTime{min-height:18px;font-size:12px;line-height:1.5;color:var(--ink4);font-variant-numeric:tabular-nums;white-space:nowrap}
/* the waiting animation's line names the step, the time and the place in the queue itself: the bar
   and the time step aside, and the card's own line shows only when it has something to add */
#waitLine:empty{display:none}
#gtProg.fx .bar,#gtProg.fx #progTime,#gtProg.fx #progText:empty{display:none}

#gtMsg{margin:0;padding:10px 12px;border-radius:12px;background:var(--card2);box-shadow:inset 0 0 0 1px var(--line2);
  font-size:13px;line-height:1.6;color:var(--ink2)}
#gtMsg.warn{background:#f59e0b1a;box-shadow:inset 0 0 0 1px #f59e0b40;color:var(--amber)}
#gtMsg.err{background:#fef2f2;box-shadow:inset 0 0 0 1px #fecaca;color:#b91c1c}
/* not open right now (switched off, or the table not installed yet): the field rests, the note says why */
#nameCard.is-off #txt,#nameCard.is-off .gthelp{opacity:.5}

/* ---------- the row menu: the name drawn small in a disc, one per way of breaking it ----------
   A button that opens a list under it (a listbox: arrows, Enter, Escape). Each disc wears the chosen
   colours -- the base round it, the emblem on the letters -- in the waiting animation's bubble font. */
/* the disc: rows of letters, each sized by griptok.js to the width the circle has there */
.mini{position:relative;width:44px;height:44px;flex:none;border-radius:50%;display:flex;flex-direction:column;align-items:center;justify-content:center;
  background:var(--mb,#faf9f6);box-shadow:inset 0 0 0 1px #0f172a24;overflow:hidden;color:var(--me,#1f1f22)}
.mini i{display:block;font-style:normal;line-height:.92;white-space:pre;letter-spacing:-.01em;
  font-family:ui-rounded,'SF Pro Rounded','Arial Rounded MT Bold','Varela Round',system-ui,sans-serif;font-weight:800}
.mini.wf i{font-family:'GT Bubble',ui-rounded,'SF Pro Rounded','Arial Rounded MT Bold',system-ui,sans-serif;font-weight:400}
/* "ให้ระบบจัดให้": a wand where the rows would be */
.mini.auto svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}

/* ---------- outcome: the drawn picture, what the check read ---------- */
#resultCard{gap:10px;animation:gtup .35s var(--spring)}
.gtres{display:flex;align-items:center;gap:12px}
#picThumb{position:relative;flex:none;width:76px;height:76px;padding:0;border:0;border-radius:14px;background:#fff;
  box-shadow:0 0 0 1px #0f172a1f;overflow:hidden}
#picThumb img{display:block;width:100%;height:100%;object-fit:contain}
/* the shown picture carries the watermark, and is not offered for saving: no long-press callout, no
   drag, no selection (griptok.js also turns the context menu away over it and over the stage) */
#picThumb img,#imgBig{-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;-webkit-user-drag:none;pointer-events:none}
#picThumb img:not([src]),#picThumb img[src=""]{visibility:hidden}

/* a magnifier in the corner: the picture opens full size */
#picThumb::after{content:'';position:absolute;right:4px;bottom:4px;width:20px;height:20px;border-radius:7px;
  box-shadow:0 0 0 1px #0f172a1f;background:#fffffff0 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23334155' stroke-width='2.4' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5M11 8v6M8 11h6'/%3E%3C/svg%3E") center/13px no-repeat}
.gtres .tx{flex:1;min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:3px}
.gtres .tx b{font-size:18px;font-weight:700;line-height:1.3;letter-spacing:.08em;overflow-wrap:anywhere}
#resRead{font-size:12px;color:var(--ink3);overflow-wrap:anywhere}
.chk{display:inline-flex;align-items:center;gap:6px;min-height:24px;padding:2px 10px 2px 8px;border-radius:999px;
  font-size:12px;font-weight:600;line-height:1.3}
.chk::before{content:'';width:7px;height:7px;flex:none;border-radius:50%;background:currentColor}
.chk.ok{background:#dcfce7;color:var(--green-ink)}
.chk.bad{background:#fef3c7;color:var(--amber)}
.chk.na{background:#0f172a0d;color:var(--ink3)}
#resNote{margin:0;font-size:12px;line-height:1.6;color:var(--ink3)}
#resNote.warn{color:var(--amber)}
.gtfree{min-height:48px;border-radius:12px;border:1px solid #22c55e80;background:#22c55e14;color:var(--green-ink);
  font-size:14px;font-weight:700}
.gtfree:hover{background:#22c55e26}

/* ---------- colours: emblem (table A) / base (table B) ---------- */
#colourCard .segs button{display:flex;align-items:center;justify-content:center;gap:8px}
/* the size buttons: the step's price over 4 cm under the size (griptok.js renderSize) */
#sizeCard .segs button{display:flex;flex-direction:column;align-items:center;justify-content:center;line-height:1.15}
#sizeCard .segs button small{font-size:11px;font-weight:600;opacity:.75}
#sizeCard .segs button small:empty{display:none}
#sizeCard .segs button[hidden]{display:none}
/* 5 cm is the size most people order (10 of the first 20 orders after sizes came, 2026-10-17): said so on it
   (ยู) -- a claim the orders stand behind, to be taken off if they stop doing so */
#sizeCard .segs button{position:relative}
#sizeCard .segs button .hot{position:absolute;top:-9px;right:6px;padding:1px 7px;border-radius:999px;background:#f97316;color:#fff;
  font-size:10px;font-weight:700;line-height:16px;letter-spacing:.01em;box-shadow:0 1px 3px #0f172a33;pointer-events:none}
#colourCard .segs button i{width:16px;height:16px;flex:none;border-radius:50%;box-shadow:inset 0 0 0 1px #0f172a33}
#colourCard .segs button[aria-pressed="true"] i{box-shadow:inset 0 0 0 1px #0f172a33,0 0 0 2px #ffffffd9}
#colNow{margin:0;padding:0 2px;font-size:13px;color:var(--ink2)}
#sameNote{margin:0;padding:8px 10px;border-radius:10px;background:#f59e0b14;color:var(--amber);font-size:12px;line-height:1.5}

/* ---------- confirm sheet: the name as tiles, one per letter, sized so the longest row fits ----------
   A word longer than a row (10 letters) comes in even rows of its own, close under one another (.r);
   words sit further apart, so a word that wraps still reads as one. */
#cfLetters{container-type:inline-size;display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:center;gap:12px 16px;padding:18px 0 6px}
#cfLetters .w{display:flex;flex-direction:column;align-items:center;gap:4px}
#cfLetters .r{display:flex;gap:4px}
#cfLetters .l{--tw:clamp(20px,calc((100vw - 84px) / var(--n,8)),40px);width:var(--tw);height:calc(var(--tw) * 1.2);
  border-radius:calc(var(--tw) * .25);background:#faf9f6;box-shadow:inset 0 -3px 0 #0f172a14,0 0 0 1px #0f172a1f;
  display:grid;place-items:center;font-size:calc(var(--tw) * .56);font-weight:700;line-height:1;color:var(--ink);
  animation:gtdrop .32s var(--spring) backwards;animation-delay:calc(var(--i,0) * 28ms)}
@supports (width:1cqi){#cfLetters .l,#cfLetters .gap{--tw:min(40px,calc((100cqi - (var(--n,8) - 1) * 4px) / var(--n,8)))}}
/* the rows, picked under the tiles (griptok.js renderPick): each way drawn small, the pick ringed */
.cfpick{margin:10px 0 0}
.cfpick .lbl{display:block;margin:0 2px 6px;font-size:12px;font-weight:600;text-align:center;color:var(--ink3)}
.cfpick .opts{display:flex;flex-wrap:wrap;justify-content:center;gap:8px}
.cfpick .opt{display:flex;flex-direction:column;align-items:center;gap:4px;min-width:68px;padding:7px 8px 8px;border:1px solid #0f172a1f;
  border-radius:12px;background:#fff;font:inherit;color:var(--ink);cursor:pointer;-webkit-tap-highlight-color:transparent}
.cfpick .opt b{font-size:12px;font-weight:700;line-height:1.3}
.cfpick .opt[aria-checked="true"]{border-color:#22c55e;background:#22c55e0f;box-shadow:0 0 0 3px #22c55e2e}
.cfpick .opt:focus-visible{outline:2px solid var(--green-ink);outline-offset:2px}
/* picked rows: one line of tiles per row, closer together than words, so the break reads as the row */
#cfLetters.rows{flex-direction:column;flex-wrap:nowrap;align-items:center;gap:6px}
#cfLetters .gap{--tw:clamp(20px,calc((100vw - 84px) / var(--n,8)),40px);width:calc(var(--tw) * .45);flex:none}
.cfnote{margin:10px 4px 0;font-size:14px;font-weight:600;line-height:1.55;text-align:center;color:var(--ink);text-wrap:balance}
.cfcred{margin:8px 4px 0;font-size:12px;line-height:1.7;text-align:center;color:var(--ink3);text-wrap:balance}
.cfacts{display:flex;gap:8px;margin-top:16px}
/* A four-word name stacks into four rows of tiles, and on a short phone (320x568, 360x640) the sheet
   then scrolls: the two buttons stay pinned to its bottom edge, so confirming never needs a scroll. The
   negative bottom and margins cancel the panel's own padding (shop.css: 10px 14px 18px + the safe
   area), so nothing shows under the bar; a hairline marks where the names scroll beneath it. */
#confirmSheet .cfacts{position:sticky;z-index:1;bottom:calc(-18px - env(safe-area-inset-bottom));
  margin:6px -14px calc(-18px - env(safe-area-inset-bottom));padding:10px 14px calc(18px + env(safe-area-inset-bottom));
  background:#fff;box-shadow:0 -1px 0 var(--line2)}
.cfacts .gtghost{flex:none;padding:0 18px}
.cfacts .gtgo{flex:1;min-width:0}
#imgBig{display:block;width:100%;max-width:440px;aspect-ratio:1;object-fit:contain;margin:12px auto 0;border-radius:14px;
  background:#fff;box-shadow:0 0 0 1px #0f172a14}

/* ---------- footer: a test page, said plainly ---------- */
#gtFoot{display:flex;flex-direction:column;align-items:center;gap:4px;padding:14px 8px calc(18px + env(safe-area-inset-bottom));
  border-top:1px solid var(--line2);text-align:center;font-size:12px;line-height:1.6;color:var(--ink4)}
#gtFoot b{padding:5px 12px;border-radius:999px;background:#0f172a0d;font-size:13px;font-weight:600;color:var(--ink2)}
#gtFoot a{display:inline-block;padding:6px 0}

/* ---------- the order card: the price, what it is, the tick, the shared cart's ใส่ตะกร้า (cart.js) ---------- */
#buyCard{box-shadow:0 0 0 1.5px #22c55e66,0 12px 28px -18px #15803d66}
.gtprice{font-size:20px;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
.gtsum{margin:-4px 0 0;font-size:13px;line-height:1.55;color:var(--ink2)}
.gtack{display:flex;gap:10px;align-items:flex-start;padding:10px 12px;border-radius:12px;background:#fffbeb;
  box-shadow:inset 0 0 0 1px #f59e0b66;font-size:13px;line-height:1.5;color:#78350f;cursor:pointer}
.gtack[hidden]{display:none}
.gtack input{width:20px;height:20px;margin:0;flex:none;accent-color:var(--blue-d)}
.gtack em{display:block;font-style:normal;font-size:12px;color:#92400e}
.gtack.need{background:#fef2f2;box-shadow:inset 0 0 0 2px #dc2626;animation:gtnudge .35s}
/* shop.css docks #acts to the bottom of the keychain page; here it sits in its card */
#buyCard #acts{position:static;margin:0;padding:0;border:0;background:none;transform:none}
#buyCard #addBtn[aria-busy="true"]{background:#bbf7d0;color:var(--green-ink);opacity:1}

@keyframes gtfade{from{opacity:0}}
@keyframes gtnudge{25%{transform:translateX(-4px)}75%{transform:translateX(4px)}}
@keyframes gtpulse{50%{transform:scale(.55);opacity:.45}}
@keyframes gtsheen{to{transform:translateX(300%)}}
@keyframes gtdrop{from{transform:translateY(-8px);opacity:0}}
@keyframes gtup{from{transform:translateY(8px);opacity:0}}
@media (prefers-reduced-motion:reduce){
  #busyFx,#busyFx i,#gtProg .bar::after,#cfLetters .l,#resultCard,.gtack.need{animation:none}
  #gtProg .bar i,.gtgo,#rowBtn .chev{transition:none}
}

/* desktop: shop.css sizes the stage to the window less its 37px date strip; the view switch here is 53px */
@media (min-width:900px){
  #window{height:calc(100vh - var(--headh) - 24px - 53px)}
  @supports (height:100dvh){#window{height:calc(100dvh - var(--headh) - 24px - 53px)}}
  #stageEmpty{bottom:8px}
  #gtFoot{padding-bottom:24px}
}

/* the round (ยู, 2026-10-21: 15 designs an order): what is left under the button, the rule under the name, which
   design of the round the confirm sheet is about */
.gtleft{margin:-2px 2px 0;font-size:12.5px;line-height:1.5;text-align:center;color:var(--ink3)}
.gtleft b{font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
.gthelp.gtround{margin-top:-8px}
.cfcred .cfround{display:block;margin-bottom:2px;font-weight:600;color:var(--ink2)}
.cfcred span{display:block}
/* the designs made, to go back to: small squares in a row that scrolls sideways */
.gtstrip-row{display:flex;gap:8px;overflow-x:auto;overscroll-behavior-x:contain;margin:0 -2px;padding:2px 2px 4px;scrollbar-width:thin}
.gtstrip-row button{position:relative;flex:none;width:64px;height:64px;padding:0;border:0;border-radius:12px;overflow:hidden;
  background:#fff;box-shadow:inset 0 0 0 1px #0f172a1f;cursor:pointer;-webkit-tap-highlight-color:transparent}
/* the ring over the picture: an inset shadow on the button itself is painted under the img */
.gtstrip-row button[aria-current="true"]::after{content:'';position:absolute;inset:0;border-radius:inherit;
  box-shadow:inset 0 0 0 2.5px var(--blue);pointer-events:none}
.gtstrip-row button.wait{opacity:.5}
.gtstrip-row img{display:block;width:100%;height:100%;object-fit:cover}
.gtstrip-row .nm{display:grid;place-items:center;height:100%;padding:4px;font-size:10px;font-weight:700;line-height:1.2;
  color:var(--ink3);overflow-wrap:anywhere}
.gtstrip .gthelp{margin:-4px 2px 0}

/* the colour sets (griptok.js buildSets): shop.css's #presets and .pre, each with a small disc in the set's
   colours -- the base, and an A in the design's colour -- and the keychain's cord beside it, on the keychain only */
.pre .dots i.gtd{width:22px;height:22px;display:grid;place-items:center;font:800 12px/1 'IBM Plex Sans Thai',sans-serif;font-style:normal}
#presets:not(.key) .pre .dots i.cord{display:none}
.pre .dots{align-items:center}
#setNow{margin:-2px 0 0;padding:0 2px;font-size:13px;color:var(--ink2)}
#ownPane{display:flex;flex-direction:column;gap:12px}
#ownPane[hidden],#colMode[hidden],#presets[hidden],#setNow[hidden]{display:none}
