/* POEFixer customer portal.
   Tokens are copied verbatim from views/pages/buy.ejs so the portal and the
   purchase page are literally the same palette. What differs is density and
   the shell: a working surface, not a checkout funnel. */

:root{
  --bg:#0d0c10; --panel:#16151b; --well:#1d1b23; --line:#2b2833;
  --gold:#c9a86a; --gold-hi:#e3c98f; --gold-dim:#8a7550;
  --text:#e9e5db; --dim:#94909e; --good:#3ecf8e; --warn:#e0b45c; --bad:#ff8080;
  --mono:'Cascadia Mono',Consolas,'Courier New',monospace;
  --serif:'Palatino Linotype','Book Antiqua',Palatino,Georgia,serif;
  --sans:'Segoe UI',system-ui,-apple-system,sans-serif;
}

*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
  font-family:var(--sans);background:var(--bg);color:var(--text);
  min-height:100vh;line-height:1.5;
  background-image:radial-gradient(ellipse 640px 420px at 50% -80px,rgba(201,168,106,.07),transparent);
}
a{color:var(--gold)}
a:hover{color:var(--gold-hi)}
.pf-link{color:var(--gold);text-decoration:none;font-size:13.5px}
.pf-link:hover{text-decoration:underline}
.pf-dim{color:var(--dim)}
.pf-bad{color:var(--bad)}
.pf-small{font-size:12.5px}
.pf-mono{font-family:var(--mono)}
.pf-hide{display:none!important}

/* ── Auth pages: one centred column, the buy-page proportions ───────────── */
.pf-auth{max-width:460px;margin:0 auto;padding:48px 16px}
.pf-brand{text-align:center;margin-bottom:22px}
.pf-brand h1{font-family:var(--serif);font-weight:400;font-size:30px;letter-spacing:4px;margin:0;color:var(--gold)}
.pf-brand p{margin:4px 0 0;color:var(--dim);font-size:13px;letter-spacing:1px}
.pf-card{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:26px;box-shadow:0 18px 48px rgba(0,0,0,.45)}
.pf-card h2{font-weight:600;font-size:17px;margin:0 0 16px;letter-spacing:.2px}
/* A card heading with a control on its right. The h2 drops its own bottom
   margin, or the button sits above the baseline the heading sets and the gap
   under the row is counted twice. */
.pf-cardhead{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:16px}
.pf-cardhead h2{margin:0}

.pf-field{margin-bottom:14px}
.pf-label{display:block;font-size:12px;letter-spacing:1px;text-transform:uppercase;color:var(--dim);margin:0 0 6px}
.pf-input{
  width:100%;padding:12px 14px;border-radius:9px;border:1px solid var(--line);
  background:var(--well);color:var(--text);font-size:15px;font-family:inherit;
  transition:border-color .15s}
.pf-input:focus{outline:none;border-color:var(--gold-dim)}
/* (0,2,0) beats the shared input:focus-visible at (0,1,1), so without this a
   keyboard user gets no ring on a text field. Repeated here to win on order. */
.pf-input:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.pf-input.err{border-color:var(--bad)}
/* The minimum-gold field: as wide as the ten digits it takes (up to
   4294967295) and its spinner, not the whole panel. `block` keeps it on its
   own line under its label, where the full-width field used to wrap to. */
.pf-input.pf-input-gold{display:block;max-width:11em}
.pf-hint{font-size:12.5px;color:var(--bad);margin:6px 2px 0;min-height:16px}
.pf-hint.ok{color:var(--good)}

.pf-cta{
  width:100%;padding:13px;border:none;border-radius:10px;cursor:pointer;
  font-size:15px;font-weight:600;letter-spacing:.4px;color:#1a1408;
  background:linear-gradient(180deg,var(--gold-hi),#b08d52);
  box-shadow:0 2px 14px rgba(201,168,106,.25);transition:filter .15s,transform .05s}
.pf-cta:hover{filter:brightness(1.06)}
.pf-cta:active{transform:translateY(1px)}
/* "Continue with Google" — an <a>, so it needs its own centring; .pf-cta is
   shaped for a full-width <button>. The divider is the quiet "or" between the
   password form and the federated entry. */
.pf-or{display:flex;align-items:center;gap:12px;margin:16px 0;color:var(--dim);font-size:12px;text-transform:uppercase;letter-spacing:1px}
.pf-or::before,.pf-or::after{content:'';flex:1;height:1px;background:var(--line)}
.pf-oauth{display:flex;align-items:center;justify-content:center;gap:10px;width:100%;box-sizing:border-box;padding:12px 16px;border:1px solid var(--line);border-radius:10px;background:var(--well);color:var(--text);font-size:14px;font-weight:600;text-decoration:none;transition:border-color .15s}
.pf-oauth:hover{border-color:var(--gold-dim);color:var(--text);text-decoration:none}
.pf-oauth-icon{width:18px;height:18px;flex:none}
.pf-cta:disabled{filter:grayscale(.6) brightness(.7);cursor:not-allowed}
.pf-ghost{
  padding:10px 16px;border-radius:9px;border:1px solid var(--line);color:var(--text);
  background:transparent;font-size:13.5px;cursor:pointer;transition:border-color .15s}
.pf-ghost:hover{border-color:var(--gold-dim)}

.pf-box{margin-top:12px;padding:12px;border:1px solid var(--line);border-radius:10px;background:var(--well)}

.pf-alert{padding:11px 14px;border-radius:9px;border:1px solid var(--line);background:var(--well);font-size:13.5px;margin-bottom:16px}
.pf-alert.bad{border-color:rgba(255,128,128,.4);background:rgba(255,128,128,.10);color:var(--bad)}
.pf-alert.good{border-color:rgba(62,207,142,.4);background:rgba(62,207,142,.10);color:var(--good)}
.pf-alert.warn{border-color:rgba(224,180,92,.4);background:rgba(224,180,92,.10);color:var(--warn)}
/* The fleet update banner (Fixes 2026-09-27): one line, the admin's note under it, the Changelog link. */
.pf-service-banner .pf-service-line{display:block;font-weight:600}
.pf-service-banner .pf-service-note{display:block;margin-top:4px;color:var(--text)}
.pf-service-banner .pf-service-link{margin-top:6px;padding:0;background:none;border:0;cursor:pointer;font:inherit}

.pf-toast{
  position:fixed;right:18px;bottom:18px;z-index:60;max-width:340px;
  padding:12px 16px;border-radius:10px;border:1px solid var(--line);
  background:var(--panel);box-shadow:0 12px 32px rgba(0,0,0,.5);font-size:13.5px}
.pf-toast.bad{border-color:rgba(255,128,128,.45)}
.pf-toast.good{border-color:rgba(62,207,142,.45)}

/* The row of secondary links under a form. Lives here rather than as a style
   attribute on three templates. */
.pf-formfoot{display:flex;justify-content:space-between;gap:12px;margin-top:16px}

/* Consent row. Not .pf-label, which is the uppercase caption above a field —
   this is a sentence a person reads and agrees to. accent-color tints the
   native control rather than rebuilding it, so the keyboard and screen-reader
   behaviour stays whatever the platform's is. The help line's left margin is
   the box (16px) plus the gap (10px), so it hangs under the text, not the box. */
.pf-check{display:flex;gap:10px;align-items:flex-start;cursor:pointer;font-size:13.5px}
.pf-check input{accent-color:var(--gold);width:16px;height:16px;margin:2px 0 0;flex:none}
.pf-check-help{color:var(--dim);font-size:12.5px;line-height:1.45;margin:6px 0 0 26px}

.pf-captcha{display:flex;gap:10px;align-items:stretch}
.pf-captcha img{border-radius:9px;border:1px solid var(--line);height:56px;width:184px;flex:none;background:#161a24}
.pf-captcha input{flex:1;min-width:0;font-family:var(--mono);letter-spacing:4px;text-align:center;font-size:17px}
.pf-captcha button{flex:none;width:44px;border-radius:9px;border:1px solid var(--line);background:var(--well);color:var(--dim);font-size:19px;cursor:pointer}

/* ── Panel shell: sidebar + working surface ─────────────────────────────── */
.pf-shell{display:flex;min-height:100vh;max-width:1160px;margin:0 auto}
.pf-sidebar{
  width:220px;flex:none;border-right:1px solid var(--line);background:var(--panel);
  padding:20px 0;display:flex;flex-direction:column;gap:2px}
.pf-sidebar .pf-brand{margin:0 0 18px;padding:0 18px;text-align:left}
.pf-sidebar .pf-brand h1{font-size:20px;letter-spacing:3px}
.pf-nav-item{
  display:block;padding:10px 18px;color:var(--dim);text-decoration:none;font-size:14px;
  border-left:2px solid transparent;cursor:pointer;background:none;border-top:0;border-right:0;border-bottom:0;
  width:100%;text-align:left;font-family:inherit;transition:color .15s,border-color .15s}
.pf-nav-item:hover{color:var(--text)}
.pf-nav-item.active{color:var(--gold);border-left-color:var(--gold);background:var(--well)}
.pf-sidebar-foot{margin-top:auto;padding:12px 18px}

.pf-main{flex:1;min-width:0;padding:22px 26px 60px}
.pf-topbar{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:20px}
.pf-topbar h2{font-weight:600;font-size:19px;margin:0}
.pf-section{display:none}
.pf-section.active{display:block}

/* Dense table: single-line separators, no zebra, numbers in mono. */
.pf-table{width:100%;border-collapse:collapse;font-size:13.5px}
.pf-table th{
  text-align:left;font-size:11px;letter-spacing:1px;text-transform:uppercase;color:var(--dim);
  font-weight:600;padding:8px 10px;border-bottom:1px solid var(--line)}
.pf-table td{padding:9px 10px;border-bottom:1px solid var(--line)}
/* A heading held to its column's right edge over right-held content — the
   Trade table's Controls, whose buttons .pf-controls holds at flex-end. */
.pf-table th.pf-col-end{text-align:right}
.pf-table tbody tr:hover{background:var(--well)}
.pf-table .num{text-align:right;font-family:var(--mono)}
.pf-table .money{text-align:right;font-family:var(--mono);color:var(--gold-hi)}
.pf-table-wrap{overflow-x:auto}

/* Recent activity: compact rows, category tabs and a server-backed pager. */
.pf-feed-size{display:flex;align-items:center;gap:7px;color:var(--dim);font-size:12.5px}
.pf-feed-size .pf-input{width:auto;min-width:72px;padding:7px 9px}
.pf-feed-tabs{display:flex;gap:7px;flex-wrap:wrap;margin:0 0 12px}
.pf-feed-tab{padding:7px 12px}
.pf-feed-tab.active{border-color:var(--gold-dim);color:var(--gold-hi)}
.pf-feed-row td{padding:6px 10px;line-height:1.3;vertical-align:top}
.pf-feed-when{white-space:nowrap}
.pf-feed-footer{display:flex;align-items:center;justify-content:space-between;
  gap:12px;padding-top:12px;color:var(--dim);font-size:12.5px}
.pf-feed-pager{display:flex;align-items:center;gap:5px}

.pf-badge{display:inline-block;padding:2px 10px;border-radius:999px;font-size:12.5px;
  background:rgba(148,144,158,.12);border:1px solid rgba(148,144,158,.4);color:var(--dim)}
.pf-badge.good{background:rgba(62,207,142,.12);border-color:rgba(62,207,142,.4);color:var(--good)}
.pf-badge.warn{background:rgba(224,180,92,.12);border-color:rgba(224,180,92,.4);color:var(--warn)}
/* A purchase under way: blue, the log's own info colour (.pf-tl-status.info),
   so it never reads as Monitoring's green. */
.pf-badge.info{background:rgba(80,130,220,.13);border-color:rgba(120,168,255,.42);color:#78a8ff}
.pf-badge.bad{background:rgba(255,128,128,.12);border-color:rgba(255,128,128,.4);color:var(--bad)}
/* The waiting state of the Game accounts card (stage A, 2026-09-23). The
   pressed control's label carries its own ellipsis, so no animated dots. */
.pf-wait{margin:6px 0 10px}
.pf-busy{opacity:.85}
.pf-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--dim);margin-right:7px}
.pf-dot.good{background:var(--good)}
.pf-dot.warn{background:var(--warn)}
.pf-dot.bad{background:var(--bad)}

.pf-empty{
  border:1px dashed var(--line);border-radius:12px;padding:34px 20px;text-align:center;color:var(--dim)}
.pf-empty h3{color:var(--text);font-weight:600;font-size:15px;margin:0 0 6px}

/* The buy row: two fields and the button on one line. Both .pf-input and
   .pf-cta are width:100% — the proportions a single-column form wants — which
   here would stack three controls full-bleed down the card. Sized to content
   instead, and the fields drop their form margin so every control shares one
   baseline. */
.pf-buy{display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap;margin-top:14px}
.pf-buy .pf-field{margin-bottom:0;flex:0 1 auto;min-width:0}
.pf-buy .pf-input,.pf-buy .pf-cta{width:auto;min-width:112px}
/* A quantity box holds one or two digits; at the shared 112px floor it read as
   a text field that had been left empty. The rail select is the opposite case:
   its longest option is "USDT (TRC-20)", and below this it truncates. */
.pf-buy input[type="number"].pf-input{width:96px;min-width:0}
.pf-buy select.pf-input{min-width:188px}
.pf-realm-picker{display:flex;align-items:center;gap:8px;min-width:0;max-width:100%}
.pf-buy .pf-realm-picker select.pf-input{min-width:0;max-width:100%;flex:1 1 auto}
.pf-realm-best{flex:0 0 auto;white-space:nowrap;margin:0}
.pf-buy .pf-cta{flex:0 0 auto}
/* The lone configured rail, stated rather than offered as a choice of one. Not
   a disabled .pf-input, which would draw a control and then refuse it: this is
   text, padded to share the baseline the fields and the button sit on. */
.pf-buy-one{margin:0;padding:12px 0;font-size:15px}

/* Billing decisions are four independent commercial actions. Two columns keep
   them scannable on a desktop; the existing narrow-screen gate below folds
   them to one without changing DOM order or keyboard order. */
.pf-billing-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;margin-bottom:16px}
/* Each card is a column so the three things a customer looks for — the
   heading, the form, the button — land on the same line as its neighbour's.
   Left to content the four intros run one to three lines, and the forms under
   them began at four different heights inside one tidy grid. */
.pf-billing-grid>.pf-card{display:flex;flex-direction:column;margin-bottom:0}
.pf-billing-grid>.pf-card>p:first-of-type{margin:0 0 2px;min-height:38px}
/* The error line takes the slack. Without it a card taller than its neighbour
   spreads the difference through its own form, which is the one place the
   spacing has to stay regular. */
.pf-billing-grid>.pf-card>p.pf-bad:last-child{margin-top:auto;margin-bottom:0}
/* The extend target is hidden until "Extend an existing subscription" is
   chosen, which is most of the time. As a grid that left the visible select in
   a half-width column, cutting its own option text off mid-word; as a flex row
   the one visible field takes the width it needs. */
.pf-billing-choice{display:flex;flex-wrap:wrap;gap:12px;margin-top:14px}
.pf-billing-choice>.pf-field{flex:1 1 240px;min-width:0;margin-bottom:0}
.pf-billing-target{min-width:0}
.pf-action-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:14px}
.pf-action-row .pf-cta{width:auto}
.pf-voucher-output{margin-top:16px;border-color:var(--gold-dim)}
.pf-voucher-values{white-space:pre-wrap;overflow-wrap:anywhere;margin:14px 0 0;padding:14px;
  border:1px solid var(--line);border-radius:9px;background:var(--well);color:var(--text);
  font-family:var(--mono);font-size:13px;line-height:1.7}

/* Standing facts about a feature, as a list rather than a wall of sentences:
   each one is a separate thing the customer has to know. */
.pf-notes{margin:12px 0 0;padding-left:18px;color:var(--dim);font-size:12.5px;line-height:1.5}
.pf-notes li{margin:5px 0}

/* ── Trade: an accordion of accounts, each holding a tree of searches ─────── */
.pf-acc{border:1px solid var(--line);border-radius:12px;background:var(--panel);margin-bottom:12px}
/* The head's own radius, and it is not decoration: .pf-acc is rounded and the
   head is its first child, so the :hover fill below would otherwise paint a
   rectangle over two rounded corners. 11 rather than 12 because the fill sits
   INSIDE the 1px border — at 12 it would show as a hairline of well-colour
   outside the panel edge. Square at the bottom while the body is showing, and
   rounded all round once the body is hidden, which is the only state where the
   head is the last thing in the panel as well as the first. */
.pf-acc-head{display:flex;align-items:center;gap:12px;row-gap:5px;padding:10px 14px;
  background:none;width:100%;color:var(--text);flex-wrap:wrap;border-radius:11px 11px 0 0}
.pf-acc[data-open="0"] .pf-acc-head{border-radius:11px}
.pf-acc-head:hover{background:var(--well)}
.pf-acc-toggle{display:flex;align-items:center;gap:12px;padding:2px 0;cursor:pointer;
  background:none;border:0;text-align:left;color:var(--text);font:inherit}
.pf-acc-body{padding:0 14px 14px;border-top:1px solid var(--line)}
.pf-acc[data-open="0"] .pf-acc-body{display:none}
/* A region or live slot with nothing in it adds no gap (stage A: the accordion
   keeps fixed containers and patches or rebuilds them in place). */
[data-region]:empty,[data-live]:empty{display:none}
/* The head's right-hand summary. It holds NOTHING but the state badge now, and
   that is what pins the badge to the header's right padding edge: the save
   status used to follow it under a min-width that reserved room whether or not
   it had anything to say. margin-left:auto rather than a style attribute: the
   script builds every one of these elements and deliberately never touches
   element.style, so layout that belongs to a component lives here where it can
   be read in one place. */
.pf-acc-meta{margin-left:auto;display:flex;align-items:center;gap:12px}
/* Inline in the header row since spec 4 item 14 — no flex:1 1 100% line-break.
   It GROWS now: the cookie is a long opaque string and a 220px box showed a
   fifth of it, so the field takes whatever the name and the badge leave, down
   to a floor that still fits a readable run of it. */
.pf-secret-head{display:flex;align-items:center;gap:7px;min-width:0;flex:1 1 280px;
  max-width:560px}
.pf-secret-head .pf-input{width:auto;min-width:220px;max-width:none;flex:1 1 auto}
/* TradeNode fixes 2026-09-30: the account POESESSID's refused key — the red of a refused group's
   key (.pf-grp-head>.pf-grp-key.bad), and like it opted out of forced colours so High Contrast
   keeps the red; it keeps its size beside the growing field. */
.pf-secret-head>.pf-acc-key{display:inline-flex;align-items:center;flex:0 0 auto;color:var(--bad);
  forced-color-adjust:none}
/* A 64-character label may not push the cookie off the row. */
.pf-acc-toggle strong{max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Whatever the header has to SAY — a save status, a refused cookie — on a line
   of its own under the badge, still inside the header. flex-basis:100% is the
   line break; the script draws it only when it has content, because an empty
   one would still cost the head's row-gap. */
.pf-acc-msg{flex:1 0 100%;display:flex;align-items:center;justify-content:flex-end;
  gap:10px;margin:0;min-width:0}
.pf-acc-msg>*{margin:0}
.pf-save-status{text-align:right}
.pf-save-status.bad{color:var(--bad)}
.pf-behavior{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin:10px 0}
.pf-behavior .pf-check-help{flex-basis:100%;margin-top:0}
/* The run toggle and the add-search, add-group, log and clear buttons ride the
   switches' own row, held to the right edge by the same rule a group header's
   controls use. */
.pf-behavior>.pf-controls{margin-left:auto}

/* A group is a header and an indented body with a rail down its left, which is
   what makes the nesting readable without a second border everywhere.
   The rail is --gold-dim, the palette's muted accent edge — the same token the
   focused input border and the ghost button's hover use — so it reads as
   structure rather than as the interactive gold of a link, a CTA or the focus
   ring. --line is the other candidate and is too quiet for the job: it is the
   panel's own border colour, so the indent would not read at all. */
.pf-grp{margin-top:12px}
/* The header carries its own fill and its own radius rather than inheriting a
   parent's, so there is no corner for a hover to square off — the fault
   .pf-acc-head has. It stays rounded whether the body is showing or not: the
   body is INDENTED beside it rather than butted underneath, so the two never
   share an edge. */
.pf-grp-head{display:flex;align-items:center;gap:8px;padding:6px 10px;border-radius:8px;
  background:var(--well);font-size:13.5px}
.pf-grp-body{margin-left:9px;padding-left:9px;border-left:2px solid var(--gold-dim)}
/* Collapsed, the way an account panel is, and stamped both ways by the script:
   a group carrying no attribute renders OPEN, which is what a group made a
   moment ago should do. */
.pf-grp[data-open="0"] .pf-grp-body{display:none}
.pf-grp-count{color:var(--dim);font-size:12.5px}
/* The Trade table's fixed columns (all but Search), shared by every group's
   table and by the group header's totals cells, which stand under the
   Performance and Purchase time columns (owner, 2026-09-24). The header drops
   its right padding and each cell pads like a table cell, so both line up with
   the table's right edge (the group body is indented only on the left). The
   floor leaves Search 138 px beside the fixed 646, including the separate
   36px grip column before State. */
.pf-trade-table{table-layout:fixed;min-width:784px}
.pf-trade-table td[data-col="search"]{overflow-wrap:anywhere}
/* The remove confirmation's two words stay whole inside the fixed Controls column. */
.pf-trade-table td[data-col="controls"] .pf-ghost{white-space:nowrap;padding:8px 12px}
.pf-trade-table col.pf-cw-drag{width:36px}
.pf-trade-table td[data-col="drag"]{padding:9px 7px;vertical-align:middle;text-align:center}
.pf-trade-table col.pf-cw-state{width:120px}
.pf-trade-table col.pf-cw-perf{width:180px}
.pf-trade-table col.pf-cw-time{width:130px}
.pf-trade-table col.pf-cw-ctl{width:180px}
.pf-grp-head{padding-right:0;gap:0}
/* No flex gap: it would sit between the totals cells and shift them off the
   columns. The three leading items keep the 8px the gap used to give them. */
.pf-grp-head>[data-action="trade-group-toggle"],.pf-grp-head>[data-grp-title],.pf-grp-head>.pf-grp-count{margin-right:8px}
/* Stage C: a group's own POESESSID, beside its name — grey in use, red refused.
   Windows High Contrast forces both to the same system text colour and the icon
   paints currentColor, so the refused key opts out (as .pf-ico does) and keeps
   its red; the grey one follows the forced colours. */
.pf-grp-head>.pf-grp-key{display:inline-flex;align-items:center;margin-right:8px;color:var(--dim)}
.pf-grp-head>.pf-grp-key.bad{color:var(--bad);forced-color-adjust:none}
/* Part E: what runs on a group's address of the twenty it can run, beside the count (and, for
   an account with no named group, in its toolbar beside the free count). Its own 8px: the header
   has no flex gap. Full wears the warning colour; at narrow width the " · common IP" words give
   way to the short kind (the ≤1000 px block below). */
.pf-grp-room{font-variant-numeric:tabular-nums;color:var(--dim);font-size:12px;white-space:nowrap;margin-right:8px}
.pf-grp-room.full{color:var(--warn)}
.pf-grp-head [data-grp-title]{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pf-grp-perf,.pf-grp-time{flex:none;box-sizing:border-box;padding:0 10px;white-space:nowrap;overflow:hidden}
.pf-grp-perf{width:180px;margin-left:auto}
.pf-grp-time{width:130px;text-align:right;font-family:var(--mono);font-size:12.5px}
.pf-grp-head>.pf-controls{flex:none;box-sizing:border-box;width:180px;padding:0 10px;margin-left:0}
/* A group's settings card (stage B): under its header, lighter than a page card. */
.pf-grp-card{margin:8px 0 4px 9px;padding:14px 16px;box-shadow:none}
/* Its buttons wrap to a new line when the row is too narrow (a phone), rather
   than each shrinking and breaking its label over two or three lines. */
.pf-grp-card>.pf-controls{flex-wrap:wrap}
/* The group's POESESSID row spans the card like the Name field above it, and its
   box may shrink below the account row's 220px floor so the eye and the clear
   button stay inside the card on a 360px phone. */
.pf-grp-card .pf-secret-head{max-width:none}
.pf-grp-card .pf-secret-head .pf-input{min-width:0}
/* Drag and drop (stage B). touch-action:none on the grip only: a finger on it
   drags, a finger anywhere else still scrolls the page. The drop place is a line
   or a frame drawn by classes the script toggles in place. The grip is also a
   .pf-iconbtn, and Ungrouped's empty slot a .pf-iconslot, whose 28px widths are
   declared further down this file — hence the two-class selectors. */
.pf-iconbtn.pf-drag{width:22px;cursor:grab;touch-action:none;color:var(--dim)}
.pf-iconbtn.pf-drag:active{cursor:grabbing}
.pf-iconslot.pf-drag-slot{width:22px}
.pf-grp-head>.pf-drag,.pf-grp-head>.pf-drag-slot{margin-right:4px}
.pf-dragging{opacity:.55}
.pf-trade-table tr.pf-drop-before td{box-shadow:inset 0 2px 0 var(--gold)}
.pf-trade-table tr.pf-drop-after td{box-shadow:inset 0 -2px 0 var(--gold)}
.pf-grp.pf-drop-before{box-shadow:0 -2px 0 var(--gold)}
.pf-grp.pf-drop-after{box-shadow:0 2px 0 var(--gold)}
.pf-grp-head.pf-drop-into,.pf-grp-drop.pf-drop-into{outline:2px solid var(--gold);outline-offset:-2px}
.pf-grp-drop{display:none;margin-top:12px;padding:10px;border:1px dashed var(--gold-dim);border-radius:8px;color:var(--dim);font-size:13px;text-align:center}
.pf-acc[data-dragging="search"] .pf-grp-drop{display:block}
.pf-search-line{display:flex;align-items:flex-start;gap:6px}
.pf-search-text{min-width:0}
/* The import card (stage B): a paste box and the preview of what it would add. */
.pf-import-text{min-height:120px;font-family:var(--mono);font-size:12px;resize:vertical}
.pf-import-preview{white-space:pre-line}
/* The service changelog (owner item 7, 2026-09-24): one card per entry, and the
   "What's new" window, whose list scrolls inside the card rather than the page. */
.pf-chl-entry{border-top:1px solid var(--line);padding:12px 0}
.pf-chl-head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.pf-chl-changes{margin:6px 0 0;padding-left:20px}
.pf-chl-changes li{margin:3px 0}
.pf-chl-modal-list{max-height:60vh;overflow-y:auto;margin:4px 0 14px}
.pf-chl-modal-actions{display:flex;flex-direction:column;align-items:center;gap:10px}
/* Service notices (stage D, 2026-09-24): the catch-up window's cards. The body
   is the operator's plain text; its line breaks are kept. A long word in the
   title or the body wraps rather than widening the card past a phone. */
.pf-ntc-entry{border-top:1px solid var(--line);padding:12px 0;overflow-wrap:anywhere}
.pf-ntc-body{margin:6px 0 0;white-space:pre-line;overflow-wrap:anywhere}

/* One field and its buttons on a single line — the per-account cookie row.
   .pf-input is width:100%, which is what a stacked form wants and what would
   push every button onto its own line here. */
.pf-inline{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:6px}
.pf-inline .pf-input{flex:1;width:auto;min-width:200px}

/* The row's counters read as one block, so they are spaced rather than columned:
   four numbers in a table cell of their own would give three of them a width
   they never need. */
.pf-perf{display:inline-flex;gap:12px;font-family:var(--mono);font-size:12.5px}
/* The four numbers and the clear that empties THEM, on one line. Each row's
   counters are their own family, so each row's clear sits beside its own. */
.pf-perf-cell{display:flex;align-items:center;gap:8px}
/* Keep the clear close to the figures it resets, regardless of the cell width.
   A row without counters holds an empty .pf-iconslot here. */
.pf-perf-clear{flex:none;display:inline-flex}
.pf-perf .good{color:var(--good)}
.pf-perf .bad{color:var(--bad)}
.pf-perf .warn{color:var(--warn)}

/* The purchase-time cell's colour IS the outcome of the last attempt, so the
   class lands on the cell itself rather than on a span inside it — which is
   also what lets a test read the outcome off the cell. */
.pf-table td.good{color:var(--good)}
.pf-table td.warn{color:var(--warn)}
.pf-table td.bad{color:var(--bad)}

/* Icon buttons: an icon on a ghost fill of its own colour, like the desktop's. */
.pf-iconbtn{width:28px;height:28px;border-radius:7px;border:1px solid transparent;
  background:rgba(148,144,158,.14);color:var(--dim);cursor:pointer;font-size:13px;
  line-height:1;padding:0;display:inline-flex;align-items:center;justify-content:center;flex:none}
.pf-iconbtn:hover{background:rgba(148,144,158,.28);color:var(--text)}
.pf-iconbtn.good{background:rgba(62,207,142,.16);color:var(--good)}
.pf-iconbtn.bad{background:rgba(255,128,128,.16);color:var(--bad)}
.pf-iconbtn:disabled{opacity:.45;cursor:not-allowed}
/* The panel's icons (stage A, 2026-09-24). The shapes are Lucide's
   (https://lucide.dev); play and stop adapted. Lucide's licence:

   ISC License

   Copyright (c) 2026 Lucide Icons and Contributors

   Permission to use, copy, modify, and/or distribute this software for any
   purpose with or without fee is hereby granted, provided that the above
   copyright notice and this permission notice appear in all copies.

   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

   ---

   The following Lucide icons are derived from the Feather project:

   airplay, alert-circle, alert-octagon, alert-triangle, aperture, arrow-down-circle, arrow-down-left, arrow-down-right, arrow-down, arrow-left-circle, arrow-left, arrow-right-circle, arrow-right, arrow-up-circle, arrow-up-left, arrow-up-right, arrow-up, at-sign, calendar, cast, check, chevron-down, chevron-left, chevron-right, chevron-up, chevrons-down, chevrons-left, chevrons-right, chevrons-up, circle, clipboard, clock, code, columns, command, compass, corner-down-left, corner-down-right, corner-left-down, corner-left-up, corner-right-down, corner-right-up, corner-up-left, corner-up-right, crosshair, database, divide-circle, divide-square, dollar-sign, download, external-link, feather, frown, hash, headphones, help-circle, info, italic, key, layout, life-buoy, link-2, link, loader, lock, log-in, log-out, maximize, meh, minimize, minimize-2, minus-circle, minus-square, minus, monitor, moon, more-horizontal, more-vertical, move, music, navigation-2, navigation, octagon, pause-circle, percent, plus-circle, plus-square, plus, power, radio, rss, search, server, share, shopping-bag, sidebar, smartphone, smile, square, table-2, tablet, target, terminal, trash-2, trash, triangle, tv, type, upload, x-circle, x-octagon, x-square, x, zoom-in, zoom-out

   The MIT License (MIT) (for the icons listed above)

   Copyright (c) 2013-present Cole Bemis

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   SOFTWARE.

   One rule paints every icon: the shape is a MASK (a URL-encoded SVG in a
   data URI, which CSP img-src 'self' data: allows) and the colour is the
   button's own text colour, so .good/.bad/:hover/:disabled recolour it. The
   script builds a span.pf-ico.pf-ico-<name> — never SVG elements, which the
   panel's harness DOM cannot build and innerHTML may not carry.
   pointer-events:none keeps the span from ever being the click target: in
   WebKit a tap on it inside a DISABLED button would otherwise reach the
   delegated handler. forced-color-adjust:none is for Windows High Contrast,
   which would force the background to the system canvas and paint every icon
   as an invisible square; opted out, currentColor is the button's own forced
   text colour. */
.pf-ico{display:inline-block;width:16px;height:16px;flex:none;vertical-align:middle;
  background-color:currentColor;pointer-events:none;forced-color-adjust:none;
  -webkit-mask:var(--pf-ico) center/16px 16px no-repeat;
  mask:var(--pf-ico) center/16px 16px no-repeat}
.pf-ico-play{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='black' stroke='none'%3E%3Cpath d='M6 4.5v15a1 1 0 0 0 1.5.86l12.5-7.5a1 1 0 0 0 0-1.72L7.5 3.64A1 1 0 0 0 6 4.5z'/%3E%3C/svg%3E")}
.pf-ico-stop{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='black' stroke='none'%3E%3Crect x='5' y='5' width='14' height='14' rx='2'/%3E%3C/svg%3E")}
.pf-ico-plus{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='M12 5v14'/%3E%3C/svg%3E")}
.pf-ico-check{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m20 6-11 11-5-5'/%3E%3C/svg%3E")}
.pf-ico-pencil{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z'/%3E%3Cpath d='m15 5 4 4'/%3E%3C/svg%3E")}
.pf-ico-gear{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E")}
.pf-ico-log{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7z'/%3E%3Cpath d='M14 2v4a2 2 0 0 0 2 2h4'/%3E%3Cpath d='M16 13H8'/%3E%3Cpath d='M16 17H8'/%3E%3Cpath d='M10 9H8'/%3E%3C/svg%3E")}
.pf-ico-trash{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 6h18'/%3E%3Cpath d='M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6'/%3E%3Cpath d='M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2'/%3E%3Cpath d='M10 11v6'/%3E%3Cpath d='M14 11v6'/%3E%3C/svg%3E")}
.pf-ico-search-plus{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3Cpath d='M11 8v6'/%3E%3Cpath d='M8 11h6'/%3E%3C/svg%3E")}
.pf-ico-folder-plus{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 10v6'/%3E%3Cpath d='M9 13h6'/%3E%3Cpath d='M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2z'/%3E%3C/svg%3E")}
.pf-ico-eye{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E")}
.pf-ico-chevron-down{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")}
.pf-ico-chevron-right{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 18 6-6-6-6'/%3E%3C/svg%3E")}
.pf-ico-chevron-left{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m15 18-6-6 6-6'/%3E%3C/svg%3E")}
.pf-ico-chevrons-left{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m11 17-5-5 5-5'/%3E%3Cpath d='m18 17-5-5 5-5'/%3E%3C/svg%3E")}
.pf-ico-chevrons-right{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 17 5-5-5-5'/%3E%3Cpath d='m13 17 5-5-5-5'/%3E%3C/svg%3E")}
.pf-ico-arrow-up{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 7-7 7 7'/%3E%3Cpath d='M12 19V5'/%3E%3C/svg%3E")}
.pf-ico-arrow-down{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 5v14'/%3E%3Cpath d='m19 12-7 7-7-7'/%3E%3C/svg%3E")}
.pf-ico-x{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E")}
.pf-ico-key{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='7.5' cy='15.5' r='5.5'/%3E%3Cpath d='m21 2-9.6 9.6'/%3E%3Cpath d='m15.5 7.5 3 3L22 7l-3-3'/%3E%3C/svg%3E")}
.pf-ico-grip{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='5' r='1'/%3E%3Ccircle cx='9' cy='12' r='1'/%3E%3Ccircle cx='9' cy='19' r='1'/%3E%3Ccircle cx='15' cy='5' r='1'/%3E%3Ccircle cx='15' cy='12' r='1'/%3E%3Ccircle cx='15' cy='19' r='1'/%3E%3C/svg%3E")}
.pf-ico-download{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'/%3E%3Cpath d='m7 10 5 5 5-5'/%3E%3Cpath d='M12 15V3'/%3E%3C/svg%3E")}
.pf-ico-upload{--pf-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'/%3E%3Cpath d='m17 8-5-5-5 5'/%3E%3Cpath d='M12 3v12'/%3E%3C/svg%3E")}
/* An empty slot the size of a .pf-iconbtn: Ungrouped's header has no rename
   button, and this keeps its add and toggle at the same place as every other
   group's. A Performance cell with nothing to clear holds one too. */
.pf-iconslot{display:inline-block;width:28px;height:28px;flex:none}
/* align-items:center because this row now mixes the two button shapes: a
   .pf-ghost is ~40px tall from its own padding and a .pf-iconbtn is a fixed
   28px square, so a definite height would otherwise sit at the top of the row
   rather than beside the text it stands with. Rows holding one shape are
   unaffected. */
.pf-controls{display:flex;gap:6px;justify-content:flex-end;align-items:center}

.pf-modal{position:fixed;inset:0;z-index:70;background:rgba(0,0,0,.6);
  display:flex;align-items:center;justify-content:center;padding:24px}
.pf-modal-card{background:var(--panel);border:1px solid var(--line);border-radius:14px;
  padding:20px;max-width:900px;width:100%;max-height:80vh;overflow:auto;
  box-shadow:0 18px 48px rgba(0,0,0,.45)}
.pf-modal-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px}
.pf-modal-head h2{margin:0;font-size:17px;font-weight:600}
/* Search/group editors share the same dialog, while keeping their account's
   paint gate and autosave fields in place. No transformed/clipping ancestor. */
.pf-trade-editor{padding:20px;overscroll-behavior:contain}
body.pf-trade-editor-open{overflow:hidden}
body.pf-trade-editor-open #pf-help-pop{z-index:71}
.pf-trade-editor-card{max-width:640px;max-height:calc(100vh - 40px);max-height:calc(100dvh - 40px)}
.pf-trade-editor-card.pf-editor-wide{max-width:760px}
.pf-trade-editor-body.pf-card{margin:0;padding:0;border:0;border-radius:0;box-shadow:none;background:none}
.pf-trade-editor-body{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:16px}
.pf-trade-editor-body>.pf-field{margin:0;min-width:0}
.pf-trade-editor-body>.pf-field:first-child,.pf-trade-editor-body>.pf-editor-full,
.pf-trade-editor-body>.pf-controls,.pf-trade-editor-body>.pf-editor-warning,
.pf-trade-editor-body>.pf-label,.pf-trade-editor-body>.pf-import-text,
.pf-trade-editor-body>.pf-import-preview,.pf-trade-editor-body.pf-grp-card>.pf-field{grid-column:1/-1}
.pf-trade-editor-body .pf-input:not(textarea){height:46px;min-width:0}
.pf-trade-editor-body>.pf-controls{border-top:1px solid var(--line);padding-top:14px;margin-top:2px;gap:8px}
.pf-trade-editor .pf-iconbtn{width:36px;height:36px;flex:none}
.pf-trade-editor .pf-modal-head .pf-iconbtn{width:32px;height:32px}
.pf-trade-editor .pf-modal-head h2{display:flex;align-items:center;gap:10px}
.pf-trade-editor .pf-check-help{margin-left:0}
.pf-trade-editor .pf-secret-head{max-width:none;flex-wrap:nowrap}
.pf-trade-editor .pf-secret-head .pf-input{min-width:0}
.pf-trade-editor .pf-modal-note{margin:12px 0 0;overflow-wrap:anywhere}
.pf-trade-editor .pf-modal-note:empty{margin:0}
/* The currency filter's rows (main 2.4.8): the currency's listbox, min, max, Apply and remove —
   at most eight, added with "+ Add currency" under them. */
.pf-curfilter{display:grid;gap:6px;margin-top:10px;min-width:0}
.pf-curfilter-row{display:grid;gap:8px;align-items:center;min-width:0;
  grid-template-columns:minmax(0,3fr) minmax(0,1.4fr) minmax(0,1.4fr) auto auto}
.pf-curfilter-head .pf-label{margin:0}
.pf-trade-editor-body .pf-curfilter-row .pf-input{height:34px;width:100%;min-width:0;padding:4px 8px;font-size:14px}
.pf-curfilter-apply{font-size:12.5px;gap:6px;align-items:center;white-space:nowrap}
.pf-currency-filter>.pf-ghost{justify-self:start;margin-top:8px}
/* The currency listbox: a field-like button with the chosen currency's art and name, and — while
   open — the list under it, each entry with its art. A native <select> cannot draw an image in an
   option. Every icon is drawn into one fixed box: the art comes 64x64, Annulment 48x48. */
.pf-curpick{position:relative;min-width:0}
.pf-curpick-face{display:flex;align-items:center;gap:7px;width:100%;min-width:0;text-align:left;cursor:pointer}
.pf-curpick-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pf-curpick-face .pf-ico{flex:0 0 auto;opacity:.7}
.pf-curpick .pf-curicon,.pf-curpick .pf-curicon-none{width:22px;height:22px}
.pf-curpick-list{position:absolute;left:0;top:calc(100% + 4px);z-index:5;width:max(100%,260px);
  max-width:calc(100vw - 48px);max-height:260px;padding:4px;background:var(--panel);
  border:1px solid var(--line);border-radius:8px;box-shadow:0 12px 32px rgba(0,0,0,.5)}
.pf-curopt:focus-visible{outline:2px solid var(--gold);outline-offset:-2px}
.pf-currency-filter>.pf-editor-full{margin-top:12px}
.pf-currency-filter .pf-editor-warning{padding:12px 14px;border:1px solid var(--line);border-radius:6px;line-height:1.5}
.pf-currency-filter .pf-controls{margin-top:14px;gap:10px;flex-wrap:wrap}
/* Merchant shop listing (main 2.4.7): the Edit form's block and the group card's section — a
   switch with its "?" beside it, then the price (a whole amount and a currency), the tab and, on a
   group, the searches the rule applies to. */
.pf-shop-listing{display:grid;gap:10px;min-width:0}
.pf-shop-listing>.pf-label{margin:0}
.pf-shop-head{display:flex;align-items:center;gap:8px;min-width:0}
.pf-shop-head .pf-check{align-items:center}
.pf-shop-listing>.pf-check-help{margin-top:0}
.pf-shop-fields{display:grid;grid-template-columns:minmax(0,3fr) minmax(0,2fr);gap:12px;min-width:0}
.pf-shop-listing .pf-field{margin:0;min-width:0}
.pf-shop-price{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,3fr);gap:8px}
.pf-shop-price .pf-curpick-face{height:100%}
.pf-shop-apply{display:grid;gap:6px;max-height:220px;overflow:auto;padding:8px 10px;
  border:1px solid var(--line);border-radius:6px}
.pf-shop-apply .pf-check{font-size:13px;align-items:center;overflow-wrap:anywhere}
/* Amendment A: the shop tabs as an ordered list (.pf-ranked, the stash target tabs' pattern), across
   the whole block, each name with its up, down and remove buttons, and the any-tab hint under it. */
.pf-shop-fields .pf-shop-tabs{grid-column:1/-1}
.pf-shop-tabs .pf-ranked{margin:2px 0 6px}
.pf-shop-tabs .pf-ranked .pf-name{flex:1;min-width:0;overflow-wrap:anywhere}
.pf-shop-tabs .pf-inline{margin-bottom:4px}
.pf-shop-tabs .pf-inline .pf-input{max-width:320px}
.pf-shop-tabs>.pf-check-help{margin:0}
.pf-editor-warning{margin:0;font-size:13px;overflow-wrap:anywhere}
@media(max-width:600px){
  .pf-trade-editor{padding:12px}
  .pf-trade-editor-card{padding:16px;max-height:calc(100vh - 24px);max-height:calc(100dvh - 24px)}
  .pf-trade-editor-body{grid-template-columns:minmax(0,1fr)}
  .pf-shop-fields,.pf-shop-price{grid-template-columns:minmax(0,1fr)}
  /* A phone: the currency across the row, then min, max, Apply and remove under it. */
  .pf-curfilter-head{display:none}
  .pf-curfilter-row{grid-template-columns:minmax(0,1fr) minmax(0,1fr) auto auto;
    padding-bottom:6px;border-bottom:1px solid var(--line)}
  .pf-curfilter-row>.pf-curpick{grid-column:1/-1}
}
/* What the last Clear did, said between the head and the table. An empty one
   must take NO room: a <p>'s default margins would otherwise open a gap in the
   middle of the card for every second the modal has nothing to say, which is
   most of them. */
.pf-modal-note{margin:0 0 12px}
.pf-modal-note:empty{display:none}

/* Trade Logs keeps the desktop window's dense card list, timing trace and
   fixed footer, while allowing columns to fold on a narrow browser. */
.pf-trade-log{max-width:1080px;height:min(820px,calc(100vh - 48px));max-height:88vh;
  padding:0;overflow:hidden;display:flex;flex-direction:column}
.pf-tl-head{padding:17px 20px 14px;margin:0;border-bottom:1px solid var(--line)}
.pf-tl-head>.pf-controls{align-self:flex-start}
.pf-tl-summary{display:flex;gap:14px;margin-top:4px;color:var(--dim);font-size:12.5px}
.pf-tl-summary .good{color:var(--good)}
.pf-tl-summary .bad{color:var(--bad)}
.pf-tl-filters{display:grid;grid-template-columns:minmax(190px,1fr) 180px 140px 34px;
  align-items:end;gap:10px;padding:12px 20px;background:var(--well);border-bottom:1px solid var(--line)}
.pf-tl-filters .pf-label{margin-bottom:4px}
.pf-tl-filters .pf-input{padding:8px 10px;font-size:13.5px}
.pf-tl-dir{margin-bottom:1px;width:34px;height:34px}
.pf-trade-log>.pf-modal-note{padding:0 20px;margin:10px 0 0}
.pf-tl-list{min-height:0;flex:1;overflow-y:auto;padding:10px 14px}
.pf-tl-empty{margin:8px 0}
.pf-tl-date{display:flex;align-items:center;gap:10px;padding:7px 8px;color:var(--dim);
  font-size:11.5px;letter-spacing:.6px;text-align:center}
.pf-tl-date::before,.pf-tl-date::after{content:"";height:1px;background:var(--line);flex:1}
.pf-tl-row-wrap{margin-bottom:6px}
.pf-tl-row{position:relative;width:100%;min-height:76px;display:grid;
  grid-template-columns:54px minmax(150px,1.2fr) minmax(90px,.55fr) minmax(150px,1fr) minmax(126px,.7fr) minmax(116px,.65fr);
  gap:12px;align-items:center;padding:10px 12px 10px 16px;border:1px solid rgba(148,144,158,.22);
  border-left:4px solid var(--line);border-radius:9px;background:linear-gradient(180deg,var(--panel),rgba(22,21,27,.92));
  color:var(--text);font:inherit;text-align:left;cursor:pointer}
.pf-tl-row:hover{background:var(--well);border-color:rgba(148,144,158,.45)}
.pf-tl-row:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.pf-tl-row[aria-expanded="true"]{border-radius:9px 9px 0 0;background:var(--well)}
.pf-tl-icon{width:50px;height:52px;display:flex;align-items:center;justify-content:center;
  border:1px solid #666;border-radius:5px;background:var(--well);overflow:hidden}
.pf-tl-icon img{object-fit:contain;max-width:48px;max-height:48px}
.pf-tl-icon.unique{border-color:#af6025;box-shadow:0 0 12px rgba(175,96,37,.16)}
.pf-tl-icon.rare{border-color:#ffff77;box-shadow:0 0 12px rgba(255,255,119,.10)}
.pf-tl-icon.magic{border-color:#8888ff}.pf-tl-icon.currency{border-color:#aa9e82}.pf-tl-icon.gem{border-color:#1aa29b}
.pf-tl-placeholder{font-size:23px;color:var(--dim)}
.pf-tl-identity,.pf-tl-traits,.pf-tl-place,.pf-tl-outcome{display:flex;min-width:0;flex-direction:column;gap:2px}
.pf-tl-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13.5px}
.pf-tl-name.unique{color:#d58b50}.pf-tl-name.rare{color:#ffff77}.pf-tl-name.magic{color:#aaaaff}
.pf-tl-name.currency{color:#c7bda5}.pf-tl-name.gem{color:#35c4bc}
/* The price reads as the currency's own artwork plus a count. inline-flex with
   a baseline-independent centre keeps the glyph and the number on one line
   whatever the row's height; the icon is capped so a tall seed cannot stretch
   the row. Falls back to plain text when the catalog has no seed. */
.pf-tl-price{color:var(--gold-hi);font:12.5px var(--mono);
  display:inline-flex;align-items:center;gap:4px}
.pf-tl-price-icon{width:16px;height:16px;object-fit:contain;flex:0 0 auto}
.pf-tl-price-count{font-variant-numeric:tabular-nums}
.pf-tl-live{color:var(--gold);font-size:12px}.pf-tl-traits .bad{color:var(--bad);font-size:12px}
.pf-tl-place>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pf-tl-region{min-width:0;overflow-wrap:anywhere;color:var(--dim)}
.pf-tl-outcome{align-items:flex-end}.pf-tl-total{color:var(--gold);font:12.5px var(--mono)}
.pf-tl-force{color:var(--warn);font-size:11.5px}
.pf-tl-status{display:inline-block;max-width:100%;padding:3px 10px;border-radius:999px;border:1px solid;
  font-size:11.5px;white-space:normal;overflow-wrap:anywhere;text-align:center}
.pf-tl-status.good{color:var(--good);background:rgba(62,207,142,.12);border-color:rgba(62,207,142,.4)}
.pf-tl-status.bad{color:var(--bad);background:rgba(255,128,128,.12);border-color:rgba(255,128,128,.4)}
.pf-tl-status.warn{color:var(--warn);background:rgba(224,180,92,.12);border-color:rgba(224,180,92,.4)}
.pf-tl-status.info{color:#78a8ff;background:rgba(80,130,220,.13);border-color:rgba(120,168,255,.42)}
.pf-tl-status.neutral{color:var(--dim);background:rgba(148,144,158,.10);border-color:rgba(148,144,158,.35)}
.pf-tl-case{color:var(--dim);font:11px var(--mono);letter-spacing:.02em;white-space:nowrap}
.pf-tl-detail{padding:14px 20px 16px;border:1px solid var(--line);border-top:0;
  border-radius:0 0 9px 9px;background:var(--well)}
.pf-tl-cycle{margin:0 0 9px;color:var(--gold);font-size:13.5px;font-weight:600}
.pf-tl-stages{display:grid;gap:4px;padding-bottom:12px;border-bottom:1px solid var(--line)}
.pf-tl-stage{display:grid;grid-template-columns:minmax(130px,1fr) 82px 46px 76px;gap:8px;
  align-items:center;padding-left:13px;position:relative;font-size:12.5px}
.pf-tl-stage::before{content:"";position:absolute;left:1px;width:6px;height:6px;border-radius:50%;background:var(--good)}
.pf-tl-stage.failed::before,.pf-tl-stage.timeout::before{background:var(--bad)}
.pf-tl-stage.degraded::before{background:var(--warn)}
.pf-tl-stage.cancelled::before,.pf-tl-stage.skipped::before{background:var(--dim)}
.pf-tl-stage-outcome{text-transform:capitalize;color:var(--dim)}
.pf-tl-mod-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px;padding:12px 0}
.pf-tl-mods h4{margin:0 0 5px;color:var(--gold-dim);font-size:11.5px;text-transform:uppercase;letter-spacing:.7px}
.pf-tl-mods p{margin:2px 0;overflow-wrap:anywhere}
.pf-tl-facts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:4px 18px;
  padding-top:10px;border-top:1px solid var(--line);font-size:12.5px}
.pf-tl-line{display:flex;gap:4px;min-width:0;overflow-wrap:anywhere}
.pf-tl-footer{display:grid;grid-template-columns:1fr auto 1fr;gap:14px;align-items:center;
  padding:10px 16px;border-top:1px solid var(--line);background:var(--panel);font-size:12.5px}
.pf-tl-footcopy{display:flex;flex-direction:column}.pf-tl-pager{display:flex;align-items:center;gap:5px}
.pf-tl-pager .pf-iconbtn{width:28px;height:28px}.pf-tl-clear{justify-self:end}

@media(max-width:900px){
  #tr-log-modal{padding:8px}.pf-trade-log{height:calc(100vh - 16px);max-height:none}
  .pf-tl-filters{grid-template-columns:1fr 1fr 34px}.pf-tl-search{grid-column:1/-1}
  .pf-tl-row{grid-template-columns:48px minmax(0,1fr) auto;gap:9px}
  .pf-tl-icon{width:44px;height:48px}.pf-tl-traits{display:none}
  .pf-tl-place,.pf-tl-region{grid-column:2/3}.pf-tl-outcome{grid-column:3;grid-row:1/4}
  .pf-tl-mod-grid,.pf-tl-facts{grid-template-columns:1fr}
  .pf-tl-footer{grid-template-columns:1fr auto}.pf-tl-clear{grid-column:1/-1;justify-self:end}
}

/* A group header at narrow width (stage A narrow-width check, 2026-09-24): the
   two fixed-width totals cells (200 + 130 px) left the name no room and pushed
   the buttons out of view — on a phone, and also between ~901 and ~960 px,
   where the sidebar still takes its share and a 760-px rule left the name
   0 px. The rows keep their own numbers, so at 1000 px and below the header
   drops its totals and keeps toggle, name, count and buttons, the buttons at
   the right edge taking only their own width. The table below scrolls in
   .pf-table-wrap. */
@media(max-width:1000px){
  .pf-grp-head>.pf-grp-perf,.pf-grp-head>.pf-grp-time{display:none}
  .pf-grp-head>.pf-controls{width:auto;margin-left:auto}
  /* The counter's " · common IP" gives way to its short kind, " · own" or " · common", read
     from data-grp-room — never dropped outright: a touch screen shows no title, and an own
     group's "▶ 2/20" would read the same as a common one's (Task 15 fix round 2). */
  .pf-grp-room-ip{display:none}
  .pf-grp-room::after{content:' · ' attr(data-grp-room)}
}

@media(max-width:480px){
  .pf-tl-summary{gap:8px;flex-wrap:wrap}.pf-tl-filters{grid-template-columns:1fr 34px}
  .pf-tl-filters label:nth-child(2){grid-column:1/-1}.pf-tl-row{grid-template-columns:42px minmax(0,1fr)}
  .pf-tl-outcome{grid-column:1/-1;grid-row:auto;align-items:flex-start;flex-direction:row;flex-wrap:wrap}
  .pf-tl-place{grid-column:2}.pf-tl-stage{grid-template-columns:minmax(100px,1fr) 64px 38px 66px;gap:4px}
  .pf-tl-footer{display:flex;flex-wrap:wrap;justify-content:center}.pf-tl-footcopy{width:100%;text-align:center}
}

/* The purchase-time breakdown: the two clocks of one attempt, drawn OVER the
   page rather than in it. .pf-acc-body has no overflow of its own, so a panel
   that grew inside a row would widen the section and scroll the whole page
   sideways — which is also why the width is fixed here and read back by
   portal-trade.js (POP_WIDTH): the placement has to bound the popover before
   the browser has laid it out.
   Its left/top are the one inline style that module writes, and they are a
   measurement rather than layout — where a fixed element lands depends on where
   the cell is, which no stylesheet can know. Everything that shows or hides is
   still a class, because .pf-hide is display:none!important.
   z-index sits under .pf-modal (70) and over .pf-toast (60): the log covers the
   table this opens from, so the two are never on screen together. */
.pf-pop{position:fixed;z-index:65;width:320px;max-width:calc(100vw - 16px);
  background:var(--panel);border:1px solid var(--line);border-radius:12px;
  padding:12px 14px;box-shadow:0 14px 36px rgba(0,0,0,.5);font-size:12.5px}
.pf-pop-block{margin-bottom:8px}
.pf-pop-head{margin:0 0 6px;color:var(--dim);font-size:11.5px;line-height:1.4}
.pf-pop-table{width:100%;border-collapse:collapse}
.pf-pop-table th{text-align:left;font-size:10.5px;letter-spacing:1px;text-transform:uppercase;
  color:var(--dim);font-weight:600;padding:3px 0}
.pf-pop-table td{padding:3px 0}
.pf-pop-table .num{text-align:right;font-family:var(--mono);padding-left:10px}
.pf-pop-total td{border-top:1px solid var(--line);font-weight:600}
/* The number in the cell IS the control that opens the breakdown: a button, so
   it is reachable from a keyboard and on a touch screen, drawn as the text it
   replaces so the column still reads as a column of numbers. */
.pf-timebtn{background:none;border:0;padding:0;color:inherit;font:inherit;cursor:help;
  border-bottom:1px dotted var(--dim)}

/* ── The "?" help point (spec 4, item 9) ──────────────────────────────────
   A circled glyph beside the thing it explains. cursor:help says what it is;
   the focus ring comes from the page-wide :focus-visible rule. */
.pf-help{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;
  width:16px;height:16px;border-radius:50%;border:1px solid var(--line);background:none;
  color:var(--dim);font-size:11px;line-height:1;padding:0;margin-left:6px;
  vertical-align:middle;cursor:help;font-family:inherit}
.pf-help:hover,.pf-help:focus-visible{color:var(--text);border-color:var(--dim)}
/* The help host: multi-paragraph tips arrive as \n\n in one data-help. */
.pf-help-pop{white-space:pre-line}
/* ── Notification pop-ups (stage C) ──────────────────────────────────────────
   A fixed column at the top right, OVER the purchase-time breakdown (.pf-pop,
   65) and UNDER the log modal (.pf-modal, 70): a notification must not hide the
   dialog a customer is working in, and must not be hidden by a hover tip. The
   host passes pointer events through, so the empty column never blocks the
   page beneath it; only the cards take clicks. Bounded by the window, the
   column scrolls rather than running its bottom (Close all) off screen on a
   short one; the wheel over a card scrolls it. The dvh line follows the vh
   one: on phones 100vh is the LARGE viewport, under the browser toolbar, and a
   browser without dvh keeps the vh line. Nothing animates, so the
   reduced-motion rule at the end of this file has nothing to take away. Shown
   and hidden by .pf-hide alone — the script never writes a style. */
.pf-notify-stack{position:fixed;top:16px;right:16px;z-index:68;width:340px;
  max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);max-height:calc(100dvh - 32px);overflow-y:auto;
  display:flex;flex-direction:column;gap:8px;pointer-events:none}
.pf-notify-pop{pointer-events:auto;background:var(--panel);border:1px solid var(--line);
  border-left:3px solid var(--gold);border-radius:10px;padding:10px 12px;
  box-shadow:0 12px 32px rgba(0,0,0,.5);font-size:13px}
.pf-notify-pop-head{display:flex;align-items:flex-start;gap:8px}
.pf-notify-pop-title{flex:1;min-width:0;overflow-wrap:anywhere;font-weight:600}
.pf-notify-pop-close{flex:none;background:none;border:0;color:var(--dim);cursor:pointer;
  font-size:18px;line-height:1;padding:0 2px;font-family:inherit}
.pf-notify-pop-close:hover{color:var(--text)}
.pf-notify-currency-icon{display:inline-block;width:18px;height:18px;object-fit:contain;vertical-align:middle}
.pf-notify-pop-body{margin:4px 0 0;overflow-wrap:anywhere;white-space:pre-line;
  max-height:40vh;overflow-y:auto}
.pf-notify-pop-meta{margin:6px 0 0;color:var(--dim);font-size:11.5px}
.pf-notify-receipt{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,2fr);gap:5px 12px;
  margin:10px 0;padding:9px;border:1px solid var(--line);border-radius:8px;overflow-wrap:anywhere}
.pf-notify-receipt dt{color:var(--dim)}
.pf-notify-receipt dd{margin:0;font-weight:600;min-width:0}
.pf-notify-receipt-note{margin:7px 0;color:var(--dim);overflow-wrap:anywhere;white-space:pre-line}
.pf-notify-receipt-action{display:inline-block;margin-top:5px;color:var(--gold);font-weight:600}
.pf-notify-success{border-left:3px solid #55b98a}
.pf-notify-warning,.pf-notify-error{border-left:3px solid #dca955}
.pf-notify-more{pointer-events:auto;display:flex;align-items:center;justify-content:space-between;
  gap:10px;padding:6px 10px;border-radius:10px;background:var(--well);
  border:1px solid var(--line);color:var(--dim);font-size:12.5px}
.pf-notify-more .pf-ghost{padding:5px 10px;font-size:12.5px}
/* ── The Notifications section ──────────────────────────────────────────────
   Cards spaced like Settings' (which carries the margin inline), a row of
   actions whose Link is an <a> wearing the ghost-button look, and a table of
   checkboxes centred under their channel. */
.pf-notify-card{margin-bottom:16px}
.pf-notify-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:8px}
.pf-notify-actions a.pf-ghost{display:inline-block;text-decoration:none}
.pf-notify-matrix td.pf-notify-cell{text-align:center;vertical-align:middle}
.pf-notify-matrix th{white-space:normal}
.pf-notify-matrix th .pf-small{display:block;text-transform:none;letter-spacing:0;font-weight:400}
.pf-notify-matrix input{accent-color:var(--gold);width:16px;height:16px;cursor:pointer}
.pf-notify-matrix input:disabled{cursor:not-allowed;opacity:.5}
.pf-notify-matrix .pf-small{margin:2px 0 0}
.pf-notify-event{font-weight:600}
.pf-notify-timeout{max-width:220px;margin-top:12px}
/* Discord & Telegram on one row: a column per channel, one column at 720 px.
   The What to send headers carry each channel's whole-column toggle. */
.pf-notify-links{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px 28px}
.pf-notify-link h3{margin:0 0 6px;font-size:14px;font-weight:600}
.pf-notify-colhead{display:inline-flex;align-items:center;gap:6px}
/* Only the box is a control: the word beside it is not in a label (one click on
   it would rewrite the whole column), and a disabled box is not offered as one. */
.pf-notify-colhead input:not(:disabled){cursor:pointer}
/* Message contents: an ordered list of rows portal-notify.js builds, each a grip
   (the Trade table's .pf-iconbtn.pf-drag / .pf-iconslot.pf-drag-slot), its
   checkbox and its label; the drop line and the dragged row are classes toggled
   in place, never an inline style. */
.pf-notify-order{list-style:none;margin:16px 0;padding:0;display:flex;flex-direction:column;gap:2px;max-width:560px}
.pf-notify-row{display:flex;align-items:center;gap:8px;padding:4px 6px;border-radius:6px}
.pf-notify-row .pf-check{margin:0;align-items:center;min-width:0}
.pf-notify-row .pf-check span{overflow-wrap:anywhere}
.pf-notify-row input{flex:none;accent-color:var(--gold)}
.pf-notify-row .pf-notify-sub{margin-left:auto;font-size:12.5px;color:var(--dim)}
.pf-notify-row.pf-notify-row-pinned{opacity:.85}
.pf-notify-row.pf-dragging{opacity:.55}
.pf-notify-row.pf-drop-before{box-shadow:inset 0 2px 0 var(--gold)}
.pf-notify-row.pf-drop-after{box-shadow:inset 0 -2px 0 var(--gold)}
/* The pop-up sound: Sound and Volume beside their labels, ▶ Play under them. */
.pf-notify-sound{display:grid;grid-template-columns:auto minmax(0,230px);align-items:center;gap:8px 12px;margin-top:10px;max-width:420px}
.pf-notify-sound .pf-ghost{grid-column:2;justify-self:start}
.pf-notify-sound-switch{margin-top:14px}
/* .pf-label's bottom margin would lift Sound and Volume off their controls. */
.pf-notify-sound .pf-label{margin:0}
.pf-notify-preview-controls{display:flex;align-items:center;gap:12px;margin-top:18px}
.pf-notify-preview-controls .pf-input{max-width:230px}
.pf-notify-preview{margin:12px 0 0;padding:16px;background:var(--bg);border:1px solid var(--line);
  border-radius:10px;font:inherit;font-size:13px;line-height:1.65;white-space:pre-wrap;overflow-wrap:anywhere}
@media(max-width:720px){.pf-notify-links{grid-template-columns:1fr}}
/* Narrow: each column toggle sits above its channel word, so the What to send
   table keeps today's width and its Pop-up column needs no sideways scroll. */
@media(max-width:640px){.pf-notify-sound{grid-template-columns:1fr}.pf-notify-sound .pf-ghost{grid-column:1}
  .pf-notify-colhead{flex-direction:column;align-items:flex-start;gap:4px}
  .pf-notify-preview-controls{align-items:flex-start;flex-direction:column;gap:6px}}

/* ── Auto-stash ─────────────────────────────────────────────────────────────
   The desktop's Auto-Stash panel, at the width a browser gives it. Three
   numbers, a picture of the backpack, two ordered tab lists and a choice. */
.pf-stash{margin-top:14px;padding-top:12px;border-top:1px solid var(--line)}
/* Drawn to match a group header, and deliberately NOT wearing its classes: two
   suites count .pf-grp-head and .pf-grp-count to say what a folded group looks
   like, and a block that merely resembles one would be counted as one. */
.pf-stash-head{display:flex;align-items:center;gap:8px;padding:6px 10px;border-radius:8px;
  background:var(--well);font-size:13.5px;width:100%;border:0;color:var(--text);
  text-align:left;cursor:pointer;font-family:inherit}
.pf-stash-head:hover{background:rgba(148,144,158,.16)}
/* Air between the collapsible header and the first control (spec 4, item 10):
   nothing between them owned any vertical margin before. */
.pf-stash-lead{margin-top:10px}
.pf-stash-sum{color:var(--dim);font-size:12.5px;margin-left:auto}
/* Label left, control at a SHARED column, value right — the alignment the
   desktop measures per language rather than hardcoding.
   ⚠ ONE GRID FOR EVERY SLIDER ROW, which is the whole point and what a grid per
   row could not do: with a grid each, every label sizes its OWN first column,
   so labels of different widths start their sliders at different places and
   end them at different widths. The rows are `display:contents` so
   their cells join the parent's tracks and the widest label sizes the column
   for all of them — the desktop measures the same thing per language. */
/* The second of the two switches that decide whether the stash phase happens
   at all. 9px is the numbers grid's own row-gap below, so the pair reads as one
   block rather than as a switch with something stuck under it; .pf-field's 14px
   still separates it from the first slider. */
.pf-stash-home{margin-top:9px}
.pf-stash-nums{display:grid;grid-template-columns:max-content minmax(0,1fr) max-content;
  align-items:center;column-gap:12px;row-gap:9px;margin:10px 0 2px;font-size:13.5px}
.pf-stash-row{display:contents}
.pf-stash-val{font-family:var(--mono);font-size:12.5px;color:var(--gold-hi);
  min-width:64px;text-align:right}
/* A heading with its own control on the right, like the group header's. */
.pf-stash-sec{display:flex;align-items:center;gap:10px;margin:16px 0 8px}
.pf-stash-sec .pf-label{margin:0}
.pf-stash-sec .pf-ghost{margin-left:auto}
/* accent-color is what makes a range track and thumb take the palette without
   reimplementing the control per engine — the same one-liner .pf-check uses for
   its box. Capped in width so a slider does not stretch to the panel edge on a
   wide screen and become impossible to place. */
.pf-range{accent-color:var(--gold);width:100%;max-width:280px;height:20px;cursor:pointer}
.pf-range:disabled{cursor:not-allowed;opacity:.5}

/* The backpack: twelve columns by five rows, at the cell size and gap the
   overlay draws. Fixed tracks and not `auto-fit`, because this IS the shape of
   the thing — a grid that reflowed on a narrow screen would be a picture of a
   backpack nobody has. It scrolls instead. position:relative makes the wrap
   the containing block for the live item layer below, so the tiles scroll
   WITH the grid instead of shearing off it. */
.pf-slots-wrap{position:relative;overflow-x:auto;padding-bottom:4px}
.pf-slots{display:grid;grid-template-columns:repeat(12,28px);
  grid-auto-rows:28px;gap:2px;width:max-content}
.pf-slot{width:28px;height:28px;border-radius:3px;border:1px solid #646464;
  background:rgba(60,60,60,.8);cursor:pointer;padding:0;font-size:10px;
  line-height:1;color:var(--text);overflow:hidden;text-overflow:ellipsis}
/* Protected. The overlay's own green, kept because an operator comparing the
   two screens must not have to translate a colour. */
.pf-slot.on{background:rgba(0,180,80,.8);border-color:rgba(0,180,80,.95)}
.pf-slot.on.pending{background:rgba(185,135,25,.8);border-color:rgba(235,184,55,.95)}
/* Past the cap: still drawn, so the grid is a grid, but plainly not available. */
.pf-slot.dim{background:rgba(40,40,40,.6);cursor:not-allowed}
.pf-slot:disabled{cursor:not-allowed}
.pf-slot.on:hover{filter:brightness(1.15)}
/* The standalone backpack grid (outside the auto-stash block) reuses .pf-slot
   for identical geometry and colour; this modifier takes back the two
   interactive affordances the base class carries — its cells are a picture,
   not controls. */
.pf-slot-ro{cursor:default}
.pf-slot-ro.on:hover{filter:none}

/* ── The live backpack, drawn over the grid ─────────────────────────────────
   THE ITEM LAYER SITS ABOVE THE CELLS, NOT BELOW: .pf-slot is 80% opaque, so
   an under-layer is occluded whatever the z-order. pointer-events:none keeps
   the left-click prefix press and the right-click currency picker on the
   buttons underneath. Geometry is THESE static classes and never an inline
   style — the suite pins portal-trade.js to exactly one setAttribute('style'),
   the popover anchor. The pitch is 30px — a 28px cell plus the 2px gap, held
   by the *{box-sizing:border-box} at the top of this file — and a tile spans
   n*30−2 so it covers its cells and stops inside the gap. */
.pf-items{position:absolute;top:0;left:0;pointer-events:none}
.pf-item{position:absolute;border:0;border-radius:3px;
  background:rgba(90,70,30,.55);font-size:9px;line-height:1.1;color:var(--text);
  overflow:hidden;padding:1px 2px}
/* ABOVE the repeated cell edges. They used to sit over it, so a 2x2 or larger
   item was drawn with grid lines running across its artwork — the cell mirror
   winning over the thing it is a mirror of. The edges stay, one layer down:
   where the art is transparent the protected/unprotected boundary still reads,
   and every cell the item does not cover keeps its own edge at full strength. */
.pf-item-image{position:absolute;inset:2px;width:calc(100% - 4px);height:calc(100% - 4px);
  object-fit:contain;pointer-events:none;z-index:2}
.pf-item-placeholder{display:block;position:relative;z-index:1}
.pf-item.has-icon .pf-item-placeholder{display:none}
.pf-item.has-icon.pf-item-icon-failed .pf-item-image{display:none}
.pf-item.has-icon.pf-item-icon-failed .pf-item-placeholder{display:block}
.pf-item-count{position:absolute;right:2px;bottom:2px;z-index:3;padding:1px 2px;
  border-radius:3px;background:rgba(15,15,15,.8);font-size:9px;line-height:1;color:#fff}
/* Each covered cell's real selected/unselected edge, repeated inside the tile
   because .pf-slot is 80% opaque and would otherwise hide it. UNDER the item
   image: the mirror must not deface what it mirrors. These spans are visual
   only; the buttons underneath remain the interaction source. */
.pf-item-cell-edge{position:absolute;width:28px;height:28px;z-index:1;pointer-events:none;
  border:1px solid #646464;border-radius:3px}
.pf-item-cell-edge.on{border-color:rgba(0,180,80,.95)}
.pf-item-cell-edge.on.pending{border-color:rgba(235,184,55,.95)}

/* ── What each protected cell is PINNED to, over the cells ──────────────────
   A THIRD LAYER, drawn after the item tiles: the pin used to be the cell
   button's own text, and the tile layer is absolutely positioned in the same
   stacking context, so it painted straight over it — 55%-opaque brown for a
   text tile, and the artwork itself for one with an icon.

   ONLY ON A CELL NO ITEM COVERS (owner, 2026-09-24). A covered cell already
   shows what is in it — the item's artwork, or its name — and the smaller
   top-left copy of the pinned currency that used to sit on it said the same
   thing twice; the cell's tooltip and accessible name still name the pin.
   pointer-events:none keeps the prefix press and the picker on the button
   underneath, as with the tile layer. Geometry is the same static pf-it-x/y
   classes, never an inline style. */
.pf-pins{position:absolute;top:0;left:0;pointer-events:none;z-index:4}
.pf-pin-mark{position:absolute;width:28px;height:28px}
/* ONE SIZE: the whole cell, inset 2px. On an empty cell the pin is the only
   thing there is to show, so it takes the cell — which is how the overlay draws
   it and what a customer expects to be able to read at a glance. */
.pf-pin-chip{position:absolute;left:2px;top:2px;height:24px;min-width:24px;
  border-radius:4px;background:rgba(15,15,15,.85);border:1px solid rgba(0,180,80,.95);
  overflow:hidden}
.pf-pin-chip.pending{border-color:rgba(235,184,55,.95)}
/* Sized by the chip rather than in absolute pixels: under the *{box-sizing}
   at the top of this file the chip's border eats into its own box, so a child
   given the chip's OUTER height is clipped by exactly the border width. The
   floor is the chip's inner width, 24px less its two 1px borders. */
.pf-pin-icon{display:block;width:100%;height:100%;min-width:22px;object-fit:contain}
.pf-pin-text{display:block;padding:0 3px;font-size:11px;line-height:22px;color:#fff;
  white-space:nowrap}
.pf-it-x0{left:0}      .pf-it-x1{left:30px}   .pf-it-x2{left:60px}
.pf-it-x3{left:90px}   .pf-it-x4{left:120px}  .pf-it-x5{left:150px}
.pf-it-x6{left:180px}  .pf-it-x7{left:210px}  .pf-it-x8{left:240px}
.pf-it-x9{left:270px}  .pf-it-x10{left:300px} .pf-it-x11{left:330px}
.pf-it-y0{top:0}       .pf-it-y1{top:30px}    .pf-it-y2{top:60px}
.pf-it-y3{top:90px}    .pf-it-y4{top:120px}
.pf-it-w1{width:28px}  .pf-it-w2{width:58px}  .pf-it-w3{width:88px}
.pf-it-w4{width:118px} .pf-it-w5{width:148px} .pf-it-w6{width:178px}
.pf-it-w7{width:208px} .pf-it-w8{width:238px} .pf-it-w9{width:268px}
.pf-it-w10{width:298px}.pf-it-w11{width:328px}.pf-it-w12{width:358px}
.pf-it-h1{height:28px} .pf-it-h2{height:58px} .pf-it-h3{height:88px}
.pf-it-h4{height:118px}.pf-it-h5{height:148px}

/* An ordered list somebody typed: the position, the name, and a way to drop it.
   Numbered because the ORDER is the setting — tabs are tried first to last. */
.pf-ranked{list-style:none;margin:6px 0;padding:0}
.pf-ranked li{display:flex;align-items:center;gap:8px;padding:3px 0;font-size:13.5px}
.pf-ranked .pf-rank{color:var(--dim);font-family:var(--mono);font-size:12.5px;min-width:18px}
.pf-ranked .pf-name{color:var(--gold-hi)}
/* A tab name is a word, not a paragraph. Unbounded, .pf-input's width:100%
   stretches it to the panel and the Add beside it ends up a screen away.
   SCOPED TO THE STASH BLOCK: the only other .pf-inline on this page is the
   cookie row, and narrowing that one too is not what this rule is about. */
.pf-stash .pf-inline .pf-input{max-width:320px}

/* What is pinned where, as one compact row per cell rather than a stack of
   full-width fields. The fast path is right-clicking the cell; this is the
   keyboard one, and it is folded away until asked for. */
.pf-pin{display:grid;grid-template-columns:max-content minmax(0,260px) max-content;
  align-items:center;column-gap:10px;row-gap:6px;margin:4px 0 2px}
.pf-pin .pf-cell{color:var(--dim);font-size:12.5px;font-family:var(--mono)}
.pf-pin .pf-input{width:100%;max-width:none}

/* The currency picker: a fixed popover placed against the cell, like the
   purchase-time breakdown it borrows its geometry from. */
.pf-curpop{padding:10px}
.pf-curpop .pf-input{width:100%;margin-bottom:8px}
.pf-curlist{max-height:220px;overflow-y:auto;margin:0;padding:0;list-style:none}
.pf-curlist li{margin:0}
/* The row is a flex line so the artwork and the name share a baseline and a
   name that wraps does not slide under its own icon. A currency the icon cache
   has not answered for yet simply has no img, and the reserved box keeps every
   name in the list on one left edge rather than letting rows jitter as icons
   arrive. */
.pf-curopt{display:flex;align-items:center;gap:7px;width:100%;text-align:left;
  background:none;border:0;color:var(--text);font:inherit;padding:5px 7px;
  border-radius:6px;cursor:pointer}
.pf-curopt:hover{background:var(--well);color:var(--gold-hi)}
.pf-curopt.on{color:var(--gold-hi)}
.pf-curicon{flex:0 0 auto;width:20px;height:20px;object-fit:contain}
.pf-curicon-none{flex:0 0 auto;width:20px;height:20px}
.pf-curfoot{display:flex;gap:8px;margin-top:8px}
/* The picker's amount step (the overlay's amount dialog): the currency it is
   for, then the number beside the stack maximum on one line. The field is
   narrowed here — the picker's own rule above makes every field in it full
   width, and a four-digit number does not need the popover's width. */
.pf-curname{display:flex;align-items:center;gap:7px;margin:4px 0 6px;
  color:var(--gold-hi);font-weight:600}
.pf-curamount{display:flex;align-items:center;gap:8px;margin-top:6px}
.pf-curpop .pf-curamount .pf-input{width:7em;margin-bottom:0}
.pf-curmax{color:var(--dim);font-family:var(--mono);font-size:12.5px}


/* One choice as a list, the "?" beside it explaining the option chosen. */
.pf-select-row{display:flex;align-items:center;gap:6px}
.pf-select{width:auto;min-width:220px;padding:8px 10px}

a:focus-visible,button:focus-visible,input:focus-visible,.pf-nav-item:focus-visible{
  outline:2px solid var(--gold);outline-offset:2px}

/* ── Settings security ────────────────────────────────────────────────────
   Scoped to pf-security-*; the shared .pf-field/.pf-input/.pf-card spacing is
   deliberately untouched, since every other card on the panel wears it too. */
.pf-security-form{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:0 16px;align-items:start}
/* The rows that must not be halved: a hint, a heading, a confirmation. */
.pf-security-wide{grid-column:1/-1}
.pf-security-actions{grid-column:1/-1;display:flex;align-items:center;gap:12px;
  flex-wrap:wrap;margin-top:6px}
.pf-security-actions .pf-cta,.pf-security-actions .pf-ghost{width:auto;min-width:140px}
/* A password field and the control that shows it: one row, with the button
   sized to its own text so the input keeps the width every other field wears.
   The padding is the input's, not .pf-ghost's, or the two ends of the row sit
   at different heights. */
.pf-secret-row{display:flex;align-items:center;gap:8px}
.pf-secret-row .pf-input{flex:1 1 auto;min-width:0}
.pf-secret-eye{flex:0 0 auto;padding:12px 14px;min-width:70px}
.pf-security-state{margin:0 0 6px;font-size:13.5px}
.pf-security-qr{display:block;width:180px;height:180px;margin:10px 0;border-radius:10px;
  border:1px solid var(--line);background:#fff}
/* The base32 key is read back character by character off a phone screen. */
.pf-security-secret{margin:0 0 10px;font-size:14px;letter-spacing:2px;
  color:var(--gold-hi);overflow-wrap:anywhere}
.pf-security-codes{list-style:none;margin:12px 0 0;padding:0;display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
.pf-security-code{font-family:var(--mono);font-size:13px;padding:8px 10px;
  border:1px solid var(--line);border-radius:8px;background:var(--well);
  color:var(--gold-hi);overflow-wrap:anywhere}

@media (max-width:900px){
  .pf-security-form,.pf-security-codes{grid-template-columns:1fr}
  .pf-billing-grid{grid-template-columns:1fr}
  .pf-shell{flex-direction:column}
  .pf-sidebar{width:auto;border-right:0;border-bottom:1px solid var(--line);
    flex-direction:row;overflow-x:auto;padding:10px 8px;gap:4px}
  .pf-sidebar .pf-brand,.pf-sidebar-foot{display:none}
  .pf-nav-item{border-left:0;border-bottom:2px solid transparent;white-space:nowrap;padding:8px 12px}
  .pf-nav-item.active{border-left:0;border-bottom-color:var(--gold)}
  .pf-main{padding:18px 14px 48px}
  /* A phone: the full width less 10px each side, where 340px would not fit. */
  .pf-notify-stack{top:10px;right:10px;left:10px;width:auto;max-width:none;
    max-height:calc(100vh - 20px);max-height:calc(100dvh - 20px)}
}

@media (prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important}
}
/* The administrator preview shares projections, while controls cannot change them. */
.pf-admin-preview [data-preview-mutation] { display: none !important; }
.pf-admin-preview .pf-slot { cursor: default; }
.pf-admin-preview .pf-slot.on:hover { filter: none; }
.pf-admin-preview #ga-add-card,
.pf-admin-preview #bill-buy,
.pf-admin-preview #bill-redeem,
.pf-admin-preview #bill-credit-apply { display: none !important; }
