/* ==== THE ERROR KIT (PKG ERR1002, 2026-10-02) ====
   Dmitry 2026-10-02: every error Hormozi-clear, the field marked, one look everywhere, polished motion. L1 "never one
   word on another line"; L2 every message is ONE line, the bold reason and the fix side by side. Three shapes, one red:
     .ok-msg  the line under a field (slot always in the page, opens in 240 ms; the content below glides down)
     .ok-box  the one-line box right above a button, as wide as it, centred
     page     a dead link: one line and its button (in the page's own template)
   Words: config.py (ERR_*); behaviour: og-errors.js; gate: tests/test_err1002_error_kit_2026_10_02.py. */
:root{--ok-red:#b42318;--ok-red-bg:#fef3f2;--ok-red-line:#f6cfca;--ok-halo:rgba(180,35,24,.14);--ok-mute:#676767;--ok-ink:#010101;
  --ok-ease:cubic-bezier(.23,1,.32,1);--ok-font:var(--b-font,"Hurme geometric sans 4",Arial,sans-serif)}

/* the field mark: one red border, the red halo only while typing in it */
[data-field].is-bad .ck-field,[data-field].is-bad .ck-box,[data-field].is-bad .og-field{border-color:var(--ok-red)!important}
[data-field].is-bad .ck-field:focus-within,[data-field].is-bad .og-field:focus-within{box-shadow:0 0 0 3px var(--ok-halo)!important}
[data-field].is-nudge .ck-field,[data-field].is-nudge .og-field{animation:ok-nudge 320ms var(--ok-ease)}
@keyframes ok-nudge{0%{transform:none}20%{transform:translateX(-4px)}45%{transform:translateX(3px)}70%{transform:translateX(-2px)}100%{transform:none}}

/* the field line: ONE line, never wraps (og-errors.js fits it to 11px at most on the smallest phones) */
.ok-msg{display:grid;grid-template-rows:0fr;transition:grid-template-rows 240ms var(--ok-ease)}
.ok-msg>div{min-height:0;overflow:hidden;visibility:hidden;transition:visibility 0s linear 240ms}
.is-bad>.ok-msg>div,.is-hint>.ok-msg>div{visibility:visible;transition:visibility 0s}
.ok-msg p{display:flex;align-items:center;gap:6px;margin:0;padding-top:7px;font:400 13px/18px var(--ok-font);color:var(--ok-red);
  white-space:nowrap;opacity:0;transform:translateY(-4px);transition:opacity 180ms var(--ok-ease),transform 240ms var(--ok-ease)}
.ok-msg p svg{flex:none;width:14px;height:14px;stroke:currentColor;fill:none;stroke-width:2.2;stroke-linecap:round}
.ok-msg p a,.ok-msg p button{all:unset;cursor:pointer;color:inherit;font-weight:600;text-decoration:underline;text-underline-offset:2px}
.ok-msg p a:focus-visible,.ok-msg p button:focus-visible{outline:2px solid #0098fe;outline-offset:2px;border-radius:3px}
.is-bad>.ok-msg,.is-hint>.ok-msg{grid-template-rows:1fr}
.is-bad>.ok-msg p,.is-hint>.ok-msg p{opacity:1;transform:none}
/* the email helper uses the same slot, in grey: a question, one tap fixes it */
.is-hint>.ok-msg p{color:var(--ok-mute)}
.is-hint>.ok-msg p b,.is-hint>.ok-msg p button{color:var(--ok-ink);font-weight:600}
.ok-l{display:block;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* MQA1003 FORMS-010: 'Did you mean @gmail.com? Use it' is the one tap that fixes the address, and it was a strip of inline text 18px
   tall. The line sits in a slot that clips whatever pokes out of it, so a button cannot be taller than its slot: the button is
   padded to a thumb (44px with its text) and the hint's slot grows to hold it, the words keep their baseline. Public pages only:
   the dashboard's own hint (account, setup) is another surface's pass. */
body:not(.app-page) .is-hint>.ok-msg p{padding-top:0}
body:not(.app-page) .is-hint>.ok-msg p button{display:inline-block;padding:13px 6px}   /* no negative margin: it made the line's scroll width exceed its box, and the kit's fitLine then shrank and wrapped it (ERR1002 L2: one line) */

/* the box: one line, the bold reason then the fix, centred above the button and as wide as it */
.ok-box{display:grid;grid-template-rows:0fr;margin:0;transition:grid-template-rows 260ms var(--ok-ease),margin 260ms var(--ok-ease)}
.ok-box>div{min-height:0;overflow:hidden;visibility:hidden;transition:visibility 0s linear 260ms}
.ok-box.is-on>div{visibility:visible;transition:visibility 0s}
.ok-box .ok-in{display:flex;justify-content:center;align-items:center;gap:8px;padding:11px 12px;border:1px solid var(--ok-red-line);border-radius:12px;
  background:var(--ok-red-bg);font:400 13px/19px var(--ok-font);color:#3b0f0b;opacity:0;transform:translateY(-6px) scale(.985);
  transition:opacity 200ms var(--ok-ease),transform 260ms var(--ok-ease)}
@media(min-width:600px){.ok-box .ok-in{font-size:14px;line-height:20px;padding:12px 14px}}
.ok-box .ok-in svg{flex:none;width:18px;height:18px;stroke:var(--ok-red);fill:none;stroke-width:2;stroke-linecap:round}
.ok-box .ok-t{margin:0;min-width:0}
.ok-box .ok-t b{color:var(--ok-red);font-weight:600}
.ok-box .ok-t a,.ok-box .ok-t button{all:unset;cursor:pointer;color:var(--ok-red);font-weight:600;text-decoration:underline;text-underline-offset:2px}
.ok-box .ok-t a:focus-visible{outline:2px solid #0098fe;outline-offset:2px;border-radius:3px}
.ok-box.is-on{grid-template-rows:1fr;margin:18px 0 0}
.ok-box.is-on .ok-in{opacity:1;transform:none}
/* in the checkout the open box sits with its button: the steps' own 26px above it, 12px to the button */
.ck-step .ok-box.is-on{margin-top:26px}
.ck-step .ok-box+.ck-act{transition:margin-top 260ms var(--ok-ease)}
.ck-step .ok-box.is-on+.ck-act{margin-top:12px}
.og-stack>.ok-box+*{margin-top:-16px;transition:margin-top 260ms var(--ok-ease)}   /* QA-4: a closed box costs the stack nothing */
.og-stack>.ok-box.is-on{margin:8px 0 0}                 /* QA-10: open, it sits with its button: 24px above, 12px to it */
.og-stack>.ok-box.is-on+*{margin-top:-4px}
.og-btn.is-busy{opacity:.85;pointer-events:none}       /* QA-13: the bot gate's short hold is seen */

/* the ring draws itself once (the payment card's family) */
.ok-ring{stroke-dasharray:63;stroke-dashoffset:63}
.ok-bar{stroke-dasharray:7;stroke-dashoffset:7}
.ok-dot{opacity:0;stroke-width:2.6}
.ok-box.is-on .ok-ring,.is-bad .ok-ring{animation:ok-draw 420ms 60ms var(--ok-ease) forwards}
.ok-box.is-on .ok-bar,.is-bad .ok-bar{animation:ok-draw 160ms 300ms var(--ok-ease) forwards}
.ok-box.is-on .ok-dot,.is-bad .ok-dot{animation:ok-fade 100ms 420ms linear forwards}
@keyframes ok-draw{to{stroke-dashoffset:0}}
@keyframes ok-fade{to{opacity:1}}

/* a dead link: one line and its button */
.ok-page{display:grid;justify-items:center;gap:18px;margin-top:28px;text-align:center}
.ok-page p{margin:0;font:600 17px/1.4 var(--ok-font);color:var(--ok-ink);white-space:nowrap}

/* the smallest phones (under 360): a little less padding, so the longest line still fits one line at 11px or more */
@media(max-width:359px){.ok-box .ok-in{padding:10px 8px;gap:6px}.ok-box .ok-in svg{width:16px;height:16px}.og-card:has(>form[data-ok]){padding:18px}}

@media(prefers-reduced-motion:reduce){
  .ok-msg,.ok-msg p,.ok-box,.ok-box .ok-in,.ok-msg>div,.ok-box>div,.og-stack>.ok-box+*{transition:none}
  [data-field].is-nudge .ck-field,[data-field].is-nudge .og-field{animation:none}
  .ok-ring,.ok-bar{stroke-dashoffset:0;animation:none!important}.ok-dot{opacity:1;animation:none!important}
}
/* ==== end of PKG ERR1002 ==== */

/* ==== PKG ERRP1002 (2026-10-02): the kit on the client dashboard (wave 2; rulings EP1-EP4) ====
   The same three shapes on every signed-in page. A Console field takes the one red border (never a second red, never a
   layout move); the line under it is the kit's own .ok-msg, inside the field's [data-field] wrapper so a stack's gap is
   spent once. The box sits right above the button that was pressed. */
.app-page [data-field].is-bad :is(.input,select,textarea,.wl-fld,.sg-box){border-color:var(--ok-red)!important;box-shadow:none}
.app-page [data-field].is-bad :is(.input,select,textarea):focus,.app-page [data-field].is-bad :is(.wl-fld,.sg-box):focus-within{box-shadow:0 0 0 3px var(--ok-halo)!important}
.app-page [data-field].is-bad .b-find-q .input{border-color:var(--ok-red)!important}
.app-page [data-field].is-nudge :is(.input,select,textarea,.wl-fld,.sg-box){animation:ok-nudge 320ms var(--ok-ease)}
.app-page [data-field].is-nudge .b-find-q{animation:ok-nudge 320ms var(--ok-ease)}
.app-page [data-field]>.ok-msg p{font-family:var(--ok-font)}
/* the wall: its field is drawn in --wl-u units; the line keeps 13px and sits 7px under the field */
.wall-page [data-field].is-bad .wl-fld{border-color:var(--ok-red)!important;box-shadow:none}
.wall-page [data-field].is-bad .wl-fld:focus-within{box-shadow:0 0 0 3px var(--ok-halo)!important}
.wall-page [data-field].is-nudge .wl-fld{animation:ok-nudge 320ms var(--ok-ease)}
/* the wall's stacks are grids with a 16u gap: a closed box or line costs them nothing, an open box keeps the gap */
.wall-page .wl-f[data-photo]{display:grid;gap:calc(16 * var(--wl-u))}
.wall-page .wl-f[data-photo]>.ok-msg p{padding-top:0}
.app-page .sg-f{display:flex;flex-direction:column;min-width:0}
/* a Console field is a label grid with a 6px gap: the closed line costs it nothing, the open one sits 7px under */
.app-page .cf[data-field]>.ok-msg p{padding-top:1px}
/* Account's photo row: the line sits under the row's value, on the value's own edge */
.app-page .ap .c-row[data-field]>.ok-msg{grid-column:2 / -1}
@media (max-width:959px){.app-page .ap .c-row[data-field]>.ok-msg{grid-column:1 / -1;padding-left:28px}}
/* the setup guide: the box sits in the foot right above Back and Continue; closed, it costs the foot's gap nothing */
.app-page .sg-foot>.ok-box.is-on{margin:0}
.app-page .sg-tfa[data-field]>.ok-msg p{padding-top:8px}
/* Messages: the composer is a flex row; its one line takes a row of its own under the box, costing nothing closed */
.app-page .chat-form:has(>.chat-say.is-bad){flex-wrap:wrap}
.app-page .chat-form>.chat-say{flex:0 0 100%;min-width:0}
.app-page .chat-form>.chat-say:not(.is-bad){display:none}
.app-page .chat-form>.chat-say .ok-msg p{padding:0 0 0 8px}
/* the photo card's doors and their line */
.app-page .pc-f[data-field]>.ok-msg p{padding-top:8px}
/* the box on the dashboard: its words keep the kit's ink (a Console paragraph colour must not grey the fix), and inside a
   grid with its own gap the gap spaces it: closed, it costs the grid nothing; open, it sits a gap above its button */
.app-page .ok-box .ok-t{color:#3b0f0b}
.app-page .ap .ap-form>.ok-box{grid-column:1 / -1}
.app-page :is(.af-form,.af-form>.af-pay,.pl-up,.ap .ap-form,.sg-foot,.wl-stack,.wl-change)>.ok-box.is-on{margin:0}
.app-page .pl-item>.pl-row>.ok-box.is-on,.app-page .pl-plans .pb>.ok-box.is-on{margin:12px 0}
/* one red: a marked row's heading stays ink (the old .c-row.is-bad heading wore a second red, #8d2017) */
.app-page .c-row[data-field].is-bad .b-tg-h h3{color:var(--c-ink)}
/* a refused target chip keeps its own word; it takes the one red */
.app-page .b-chips.is-edit li.is-refused{background:var(--ok-red-bg);color:var(--ok-red);height:auto;min-height:36px;flex-wrap:wrap;row-gap:2px}
.app-page .sg .b-chips.is-edit li.is-refused{background:var(--ok-red-bg);color:var(--ok-red)}   /* audit 11: beats the guide's own #b91c1c */
.app-page .sg .b-chips.is-edit li .b-chip-off,.app-page .b-chips.is-edit li .b-chip-off{font-style:normal;font-size:12px;font-weight:600;line-height:1.2;color:var(--ok-red)}
/* a switch that did not save says so beside itself, in the one red */
.app-page .sw-saved.is-bad{color:var(--ok-red)}
/* the Instagram search's foot: one line, the one red */
.app-page .b-drop-foot{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.app-page .b-drop-foot.is-off{color:var(--ok-red)}
.app-page .b-drop li em.b-off{color:var(--ok-red)}
@media(prefers-reduced-motion:reduce){.app-page [data-field].is-nudge :is(.input,select,textarea,.wl-fld,.sg-box),.app-page [data-field].is-nudge .b-find-q,.wall-page [data-field].is-nudge .wl-fld{animation:none}}
/* AT REST A CLOSED LINE OR BOX IS NOT LAID OUT AT ALL ON THE DASHBOARD. Every Console stack is a grid or a flex column
   with its own gap, and an item of zero height still spends one gap: measured before this rule, +6 to +24 px per field
   with no error anywhere (tests/test_errp1002 at-rest gate). Opened, it is laid out and slides open from nothing
   (@starting-style); closed, it plays its close and then leaves the layout (display, allow-discrete). An engine
   without @starting-style shows it at once, never wrong. */
.app-page [data-field]>.ok-msg{display:none;transition:grid-template-rows 240ms var(--ok-ease),display 240ms allow-discrete}
.app-page :is(.is-bad,.is-hint)>.ok-msg{display:grid}
.app-page .ok-box{display:none;transition:grid-template-rows 260ms var(--ok-ease),display 260ms allow-discrete}   /* no margin transition: the dashboard's boxes sit on their grid's gap */
.app-page .ok-box.is-on{display:grid}
@starting-style{
  .app-page :is(.is-bad,.is-hint)>.ok-msg{grid-template-rows:0fr}
  .app-page :is(.is-bad,.is-hint)>.ok-msg p{opacity:0;transform:translateY(-4px)}
  .app-page .ok-box.is-on{grid-template-rows:0fr}
  .app-page .ok-box.is-on .ok-in{opacity:0;transform:translateY(-6px) scale(.985)}
}
@media(prefers-reduced-motion:reduce){.app-page [data-field]>.ok-msg,.app-page .ok-box{transition:none}}
/* ==== end of PKG ERRP1002 ==== */
