/* SARAH showcase — floating windows.
   Ported from the SARAH app: app/client/src/Panel.jsx (+ the panel manager in
   App.jsx). Drag by the title bar, resize from all 8 edges/corners, per-window
   opacity slider, minimise to a header bar, close, click-to-focus z-order,
   side-edge snapping, Expand all / Collapse all / Move All To View / Close all.
   On phones a window opens maximised, exactly like the app does. */

#windows{position:absolute;inset:0;z-index:6;pointer-events:none}
#windows > *{pointer-events:auto}

.panel{position:absolute;display:flex;flex-direction:column}
.panel:focus{outline:none}
.panel__shell{
  width:100%;height:100%;display:flex;flex-direction:column;
  background:var(--surface);border:1px solid var(--border);border-radius:12px;
  box-shadow:var(--shadow-soft);
  backdrop-filter:blur(18px) saturate(1.2);-webkit-backdrop-filter:blur(18px) saturate(1.2);
  overflow:hidden;pointer-events:none;
}
.panel.is-focused .panel__shell{border-color:var(--border-strong);box-shadow:var(--shadow),0 0 24px var(--accent-glow)}
.panel.is-minimized .panel__shell{border-radius:10px}
.panel.is-minimized .panel__body{display:none}

.panel__head{
  display:flex;align-items:center;gap:.5rem;height:30px;flex-shrink:0;
  padding:.3rem .5rem .3rem .75rem;
  background:var(--topbar-bg);border-bottom:1px solid var(--border);
  cursor:grab;user-select:none;-webkit-user-select:none;pointer-events:auto;
}
.panel.is-minimized .panel__head{border-bottom:0}
.panel.is-dragging .panel__head{cursor:grabbing}
.panel__title{
  font-size:.78rem;font-weight:700;color:var(--text);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0;
}
.panel__op{display:flex;align-items:center;gap:.25rem;flex-shrink:0;cursor:pointer;color:var(--muted);font-size:.72rem}
.panel__op input[type=range]{width:56px;height:14px;accent-color:var(--accent);cursor:pointer;margin:0}
.panel__btn{
  background:transparent;border:1px solid var(--border);color:var(--muted);
  border-radius:6px;width:22px;height:22px;line-height:1;cursor:pointer;padding:0;
  font:inherit;font-size:.78rem;font-weight:700;flex-shrink:0;
  display:inline-flex;align-items:center;justify-content:center;
}
.panel__btn:hover{color:#fff;border-color:var(--border-strong)}
.panel__btn:focus-visible{outline:2px solid var(--gold);outline-offset:1px}
.panel__body{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;overflow:hidden;pointer-events:auto}

/* The source <div data-panel> gets cloned into .panel__body, so it sits between
   the body and .pn. Without its own flex rules it is a plain block that grows
   to fit its content: .pn then never becomes shorter than its content, so it
   never scrolls, and .panel__body's overflow:hidden just CLIPS the overflow.
   That was the "windows don't scroll" bug. This makes the wrapper a proper
   full-height flex child so .pn's own flex:1 + overflow-y:auto can do its job. */
.panel__body > [data-panel]{
  display:flex;flex-direction:column;flex:1 1 auto;min-height:0;overflow:hidden;
}

/* 8 resize handles — siblings of the shell so overflow:hidden can't clip them.
   Corners carry two letters ('nw', 'se'...); the JS joins the array into one
   string before matching, because ['nw'].indexOf('n') is -1 and corners would
   silently refuse to resize. Don't "simplify" that away. */
.panel__rs{position:absolute;z-index:10;background:transparent;touch-action:none}
.panel__rs--n{top:0;left:7px;right:7px;height:7px;cursor:ns-resize}
.panel__rs--s{bottom:0;left:7px;right:7px;height:7px;cursor:ns-resize}
.panel__rs--w{left:0;top:7px;bottom:7px;width:7px;cursor:ew-resize}
.panel__rs--e{right:0;top:7px;bottom:7px;width:7px;cursor:ew-resize}
.panel__rs--nw{top:0;left:0;width:14px;height:14px;cursor:nwse-resize;z-index:11}
.panel__rs--ne{top:0;right:0;width:14px;height:14px;cursor:nesw-resize;z-index:11}
.panel__rs--sw{bottom:0;left:0;width:14px;height:14px;cursor:nesw-resize;z-index:11}
.panel__rs--se{bottom:0;right:0;width:14px;height:14px;cursor:nwse-resize;z-index:11}

/* ---------- scrollbars: the SARAH app's thin theme bars ----------
   Same rules as the app's index.html (8px, transparent track, rounded
   thumb from --border-strong, brighter on hover). Declared on the panel
   layer rather than * so they never touch the page behind it. */
#windows *{scrollbar-width:thin;scrollbar-color:var(--border-strong) transparent}
#windows ::-webkit-scrollbar{width:8px;height:8px}
#windows ::-webkit-scrollbar-track{background:transparent}
#windows ::-webkit-scrollbar-thumb{background:var(--border-strong);border-radius:4px}
#windows ::-webkit-scrollbar-thumb:hover{background:var(--faint)}
#windows ::-webkit-scrollbar-corner{background:transparent}

/* [hidden] must always win. The browser default is [hidden]{display:none}, but
   ANY author rule that sets a display value outranks it — .pn-mp li is
   display:grid, so setting el.hidden = true changed the property and the row
   still RENDERED. That is why marketplace search looked like it did nothing.
   !important is correct here: hidden means hidden, whatever the element is. */
#windows [hidden]{display:none!important}

/* ---------- panel body content ---------- */
.pn{
  /* The scroll container. min-height:0 is what actually lets a flex child
     scroll instead of growing past the window; overscroll-behavior stops a
     flick inside a panel from scrolling the console behind it. */
  overflow-y:auto;overflow-x:hidden;flex:1 1 auto;min-height:0;
  overscroll-behavior:contain;
  padding:14px 16px 18px;color:var(--text-soft);font-size:.86rem;line-height:1.55;
}
.pn a{color:var(--accent)}
.pn a:hover{color:#fff}
.pn h3{
  font-family:var(--serif);font-weight:400;font-size:1.02rem;color:var(--text);
  margin:0 0 .35rem;line-height:1.25;
}
.pn h2{
  font-family:var(--mono);font-size:.66rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--faint);margin:1.1rem 0 .45rem;font-weight:700;
}
.pn h2:first-child{margin-top:0}
.pn h4{
  font-family:var(--mono);font-size:.66rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--faint);margin:1.1rem 0 .45rem;font-weight:700;
}
.pn p{margin:0 0 .7rem}
.pn p:last-child{margin-bottom:0}
.pn-lead{font-size:.95rem;color:var(--text)}
.pn-kicker{font-family:var(--mono);font-size:.66rem;letter-spacing:.16em;text-transform:uppercase;color:var(--accent);margin:0 0 .5rem}
.pn-list{margin:0;padding:0;list-style:none;border-top:1px solid var(--border)}
.pn-list li{padding:.6rem 0;border-bottom:1px solid var(--border)}
.pn-list b{display:block;color:var(--text);font-weight:700;font-size:.88rem}
.pn-list span{color:var(--muted);font-size:.82rem}
.pn-list--tight li{padding:.42rem 0}
.pn-quote{
  font-family:var(--serif);font-size:1rem;line-height:1.4;color:var(--text);
  border-left:3px solid var(--accent);padding-left:.8rem;margin:0 0 .9rem;
}
.pn-kv{display:grid;grid-template-columns:auto 1fr;gap:.25rem .8rem;margin:0 0 .8rem;font-size:.82rem}
.pn-kv dt{color:var(--faint);font-family:var(--mono);font-size:.7rem;letter-spacing:.08em;text-transform:uppercase;padding-top:.18rem}
.pn-kv dd{margin:0;color:var(--text-soft)}
.pn-chips{display:flex;flex-wrap:wrap;gap:.3rem;margin:0 0 .8rem;padding:0;list-style:none}
.pn-chips li{
  font-family:var(--mono);font-size:.68rem;color:var(--muted);
  border:1px solid var(--border);border-radius:999px;padding:.16rem .5rem;
}
.pn-cta{
  display:inline-block;margin-top:.9rem;font-size:.8rem;font-weight:700;
  color:var(--accent);text-decoration:none;border-bottom:2px solid transparent;
}
.pn-cta:hover{color:#fff;border-bottom-color:var(--accent)}
.pn-note{margin-top:.9rem;font-size:.72rem;color:var(--faint)}
.pn-cmp{border-top:1px solid var(--border);margin:0 0 .8rem}
.pn-cmp__row{padding:.55rem 0;border-bottom:1px solid var(--border)}
.pn-cmp__row b{color:var(--text)}
.pn-cmp__tag{font-family:var(--mono);font-size:.66rem;font-weight:700;letter-spacing:.04em}
.pn-cmp__tag--pro{color:var(--good,var(--green-dim))}
.pn-cmp__tag--win{color:var(--accent)}
.pn-cmp__tag--con{color:var(--bad,#e5484d)}
.pn-cmp__lead{
  font-family:var(--mono);font-size:.63rem;letter-spacing:.12em;text-transform:uppercase;
  color:var(--faint);margin:.6rem 0 .3rem;font-weight:700;
}
.pn-cmp__list{margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:.28rem}
.pn-cmp__list li{font-size:.82rem;color:var(--text-soft);line-height:1.45}
.pn-cmp__row b{font-size:.92rem}
.pn-figs{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:.6rem;margin:0;padding:0;list-style:none}
.pn-figs li{min-width:0}
.pn-figs img{border:1px solid var(--border);border-radius:8px;background:#111;width:100%;height:auto;display:block}
.pn-figs b{display:block;color:var(--text);font-size:.78rem;margin-top:.3rem;font-weight:700}
.pn-figs span{color:var(--muted);font-size:.72rem}
.pn details{border-bottom:1px solid var(--border);padding:.55rem 0}
.pn details:first-of-type{border-top:1px solid var(--border)}
.pn summary{cursor:pointer;color:var(--text);font-size:.86rem;font-weight:600}
.pn summary::marker{color:var(--accent)}
.pn details p{margin:.4rem 0 0;color:var(--muted);font-size:.82rem}
.pn .slot-label{display:block;margin-top:.2rem}
.pn-figs-more{margin-top:.7rem;display:block}

/* ---------- marketplace inside a window ---------- */
/* Tabs are <button>s for in-window switching, but the style is shared with <a>
   so the same control can be a link elsewhere. Styling only `.pn-tabs a` left
   the buttons as raw OS chrome — do not narrow these selectors again. */
.pn-tabs{
  display:inline-flex;gap:2px;margin:0 0 .6rem;padding:2px;
  background:rgba(0,0,0,.3);border:1px solid var(--border);border-radius:9px;
}
.pn-tabs > a,
.pn-tabs > button{
  font:inherit;font-size:.74rem;font-weight:700;line-height:1;
  appearance:none;-webkit-appearance:none;
  background:transparent;border:0;border-radius:7px;
  color:var(--muted);text-decoration:none;cursor:pointer;
  padding:.42rem .7rem;white-space:nowrap;
}
.pn-tabs > a:hover,
.pn-tabs > button:hover{color:#fff;background:rgba(255,255,255,.06)}
.pn-tabs > a:focus-visible,
.pn-tabs > button:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.pn-tabs > a.on,
.pn-tabs > button.on{
  color:var(--sunk);background:var(--accent);
  box-shadow:0 1px 0 rgba(255,255,255,.18) inset;
}

/* Search row: field, clear, and a quiet live count. */
.pn-search{display:flex;align-items:center;gap:.4rem;margin:0 0 .7rem;flex-wrap:wrap}
.pn-search .pn-field{position:relative;flex:1 1 13rem;min-width:0;display:flex}
.pn-search .pn-field::before{
  content:"⌕";position:absolute;left:.5rem;top:50%;transform:translateY(-52%);
  font-size:.9rem;color:var(--faint);pointer-events:none;
}
.pn-mp-q{
  width:100%;font:inherit;font-size:.8rem;
  background:rgba(0,0,0,.3);border:1px solid var(--border);border-radius:8px;
  color:var(--text);padding:.42rem .55rem .42rem 1.55rem;
  appearance:none;-webkit-appearance:none;
}
.pn-mp-q::placeholder{color:var(--faint)}
.pn-mp-q:hover{border-color:var(--border-strong)}
.pn-mp-q:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-glow)}
.pn-mp-count{
  font-family:var(--mono);font-size:.66rem;letter-spacing:.06em;text-transform:uppercase;
  color:var(--faint);white-space:nowrap;
}
.pn-mp-clear{
  font:inherit;font-size:.72rem;font-weight:700;cursor:pointer;
  background:transparent;border:1px solid var(--border);color:var(--muted);
  border-radius:8px;padding:.4rem .55rem;line-height:1;
}
.pn-mp-clear:hover{color:#fff;border-color:var(--border-strong)}

/* Buttons, used for downloads and buys. */
.pn-btn{
  display:inline-flex;align-items:center;gap:.3rem;
  font:inherit;font-size:.72rem;font-weight:700;line-height:1;text-decoration:none;
  cursor:pointer;background:transparent;border:1px solid var(--border);
  color:var(--muted);border-radius:8px;padding:.4rem .6rem;white-space:nowrap;
  appearance:none;-webkit-appearance:none;
}
.pn-btn:hover{color:#fff;border-color:var(--border-strong);background:rgba(255,255,255,.05)}
.pn-btn:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.pn-btn--ghost{opacity:.7}
.pn-btn--buy{border-color:var(--accent);color:var(--accent);font-weight:800}
.pn-btn--buy:hover{background:var(--accent);color:var(--sunk)}

/* One row per file. Download sits in its own column so the text can breathe. */
.pn-mp{margin:0;padding:0;list-style:none;border-top:1px solid var(--border)}
.pn-mp li{
  display:flex;gap:.6rem;align-items:center;
  padding:.5rem 0;border-bottom:1px solid var(--border);
}
.pn-mp__text{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:.12rem}
.pn-mp b{color:var(--text);font-size:.84rem;font-weight:700}
.pn-mp__cat{
  font-family:var(--mono);font-size:.62rem;letter-spacing:.07em;
  text-transform:uppercase;color:var(--faint);
}
.pn-mp__desc{color:var(--muted);font-size:.77rem;line-height:1.4}
.pn-mp .pn-btn{flex:0 0 auto}
.pn-mp .pn-btn__ext{font-family:var(--mono);font-size:.66rem;color:var(--faint)}
.pn-mp .pn-btn:hover .pn-btn__ext{color:inherit}
/* Category filter chips double as the item tags — quiet, not shouty. */
.pn-chips{display:flex;flex-wrap:wrap;gap:.3rem;margin:0 0 .8rem;padding:0;list-style:none}
.pn-chips li{
  font-family:var(--mono);font-size:.66rem;color:var(--muted);
  border:1px solid var(--border);border-radius:999px;padding:.18rem .55rem;list-style:none;
}
/* Numbered install steps. */
.pn-steps{margin:0 0 .9rem;padding-left:1.15rem;color:var(--text-soft);font-size:.81rem}
.pn-steps li{margin-bottom:.5rem;padding-left:.15rem}
.pn-steps li::marker{color:var(--accent);font-family:var(--mono);font-weight:700}
.pn-steps b{color:var(--text);display:block;margin-bottom:.1rem}
.pn-steps span{color:var(--muted);font-size:.78rem;line-height:1.45}
/* Bulk download call-to-action block. */
.pn-cta--big{font-size:.88rem}
.pn-buy{margin:0 0 .8rem;padding:0;list-style:none;border-top:1px solid var(--border)}
.pn-buy li{
  padding:.65rem 0;border-bottom:1px solid var(--border);
  display:flex;align-items:center;gap:.7rem;flex-wrap:wrap;
}
.pn-buy b{color:var(--text);font-size:.85rem;flex:1 1 9rem}
.pn-buy__price{font-family:var(--mono);font-size:.86rem;font-weight:700;color:var(--text)}
@media(max-width:520px){
  .pn-mp li{align-items:flex-start}
  .pn-mp .pn-btn{padding:.45rem .55rem}
}

/* Platform tag on a buy row, and the wrapped note under it. */
.pn-buy__plat{
  font-family:var(--mono);font-size:.62rem;font-weight:400;letter-spacing:.07em;
  text-transform:uppercase;color:var(--faint);
}
.pn-buy__note{flex:1 1 100%;margin-top:-.15rem}
.pn-buy li{align-items:baseline}

/* ---------- mobile: a window becomes a full-canvas sheet ----------
   On a phone the sheet covers the canvas, so the whole desktop idea — several
   windows open, drag one aside, click another bubble — has to be replaced with
   something that works on a 390px screen. What that means in practice:

     · one sheet at a time, filling the viewport
     · a clearly labelled way BACK to the map (the ‹ button), because otherwise
       the canvas is unreachable and you must close the window to see the map
     · controls big enough to hit with a thumb (44px is the accepted minimum)
     · no resize handles, no drag, no edge-snapping — impossible or pointless
       without a pointer, and the desk-only buttons are hidden below

   The sheet is inset from the very edges so the phone's own rounded corners and
   gesture bars do not clip the title bar. dvh, not vh: on mobile Safari and
   Chrome, vh includes the retracting URL bar, so a 100vh sheet has its bottom
   cut off until you scroll. */
@media(max-width:820px){
  .panel.is-mobile{
    position:absolute;left:6px;top:6px;right:6px;bottom:6px;
    width:auto!important;height:auto!important;
  }
  .panel.is-mobile .panel__head{
    cursor:default;
    /* Bigger title bar: 30px is a desktop size and is hard to grab or aim at. */
    height:auto;min-height:44px;padding:.35rem .45rem .35rem .55rem;gap:.4rem;
  }
  .panel.is-mobile .panel__title{font-size:.82rem}
  /* Touch targets. 34px is still under the 44px guideline, but the buttons sit
     in a 44px bar with padding around them, and going larger squeezes the title
     out of the bar entirely on a narrow screen. */
  .panel.is-mobile .panel__btn{width:34px;height:34px;font-size:1rem}
  .panel.is-mobile .panel__op{display:none}        /* opacity is a desktop nicety */
  /* Minimise makes no sense when the sheet is the whole screen. */
  .panel.is-mobile [data-act=min]{display:none}
  .panel.is-mobile .panel__body{border-radius:0 0 10px 10px}
}

/* The back button only exists on the mobile sheet; hide it if a wide window ever
   gets one (e.g. rotating a tablet). */
.panel__btn--back{display:none}
@media(max-width:820px){
  .panel.is-mobile .panel__btn--back{display:inline-flex}
}

/* Desk-only controls on the console toolbar. Dragging windows and snapping them
   to half the screen cannot be done with a thumb on a full-screen sheet, so
   those buttons would be dead weight — and each dead button makes the ones that
   DO work harder to find. */
@media(max-width:820px){
  #nh-snap,#nh-inview{display:none}
  /* Expand/collapse still mean something: they restore/minimise the sheet. */
  .app-tools .tool-btn{min-height:38px;padding:.34rem .6rem;font-size:.78rem}
}

/* Legend: a thumb needs a bigger target than a 13px dot, and the panel needs to
   stay reachable when it is open on a small screen. */
@media(max-width:520px){
  .nh-legend{left:8px;right:8px;bottom:8px;max-width:none}
  .nh-legend__pill{min-height:38px;font-size:.74rem;padding:.62rem .9rem}
  .nh-row{padding:.34rem 0;font-size:.85rem}
  .nh-dot{width:20px;height:20px}
}

/* ---------- checkout window ----------
   The buy form lives in a window now. Kept deliberately plain: nothing here
   should compete with the payment button. */
.pn-price{
  font-family:var(--mono);font-size:1.4rem;font-weight:700;color:var(--text);
  margin:.5rem 0 .2rem;line-height:1.1;
}
.pn-price s{color:var(--faint);font-size:.66em;font-weight:400;margin-right:.5rem}
.pn-save{font-size:.8rem;color:var(--green-dim);margin:0 0 .8rem}
.pn-save code{background:none;border:0;padding:0;color:inherit;font-weight:700}

/* good/bad feedback, e.g. a code that did or did not check out */
.pn-msg{
  border:1px solid var(--line);border-radius:8px;padding:.45rem .6rem;
  margin:.6rem 0;font-size:.82rem;line-height:1.45;
}
.pn-msg--good{border-color:var(--green-dim);color:var(--green-dim)}
.pn-msg--bad{border-color:#e5484d;color:#ff9a9d}
.pn-msg code{background:none;border:0;padding:0;color:inherit}

/* the buy form itself */
.pn-form{display:flex;flex-direction:column;gap:.6rem;align-items:flex-start;margin-top:.4rem}
.pn-form label{display:flex;flex-direction:column;gap:.25rem;font-size:.8rem;color:var(--muted);width:100%}
.pn-form input{
  font:inherit;font-size:.88rem;background:var(--sunk);border:1px solid var(--line);
  border-radius:7px;color:var(--text);padding:.45rem .55rem;width:100%;
}
.pn-form input:focus{outline:2px solid var(--accent);outline-offset:0;border-color:var(--accent)}
.pn-actions{display:flex;gap:.5rem;flex-wrap:wrap;align-items:center;margin-top:.2rem}
.pn-btn--ghost{background:transparent;border:1px solid var(--line);color:var(--muted)}
.pn-btn--ghost:hover{color:var(--text);border-color:var(--accent)}

/* ---------- contact window ----------
   The honeypot is moved off-screen rather than display:none, because some bots
   skip fields that are explicitly hidden. aria-hidden plus tabindex="-1" in the
   markup keeps it away from screen readers and the keyboard, so a real person
   can never reach it. */
.pn-hp{
  position:absolute;left:-9999px;top:auto;
  width:1px;height:1px;overflow:hidden;
}
.pn-contact textarea{
  font:inherit;font-size:.88rem;background:var(--sunk);border:1px solid var(--line);
  border-radius:7px;color:var(--text);padding:.5rem .55rem;width:100%;
  resize:vertical;min-height:8rem;line-height:1.5;
}
.pn-contact textarea:focus{outline:2px solid var(--accent);outline-offset:0;border-color:var(--accent)}
.pn-contact input[type=text],.pn-contact input[type=email]{
  font:inherit;font-size:.88rem;background:var(--sunk);border:1px solid var(--line);
  border-radius:7px;color:var(--text);padding:.45rem .55rem;width:100%;
}
.pn-contact input:focus{outline:2px solid var(--accent);outline-offset:0;border-color:var(--accent)}

/* ---------- Free / Premium labels ----------
   Two jobs, deliberately different in weight:

   .pn-tag      an inline micro-label. Sized to sit inside a sentence or a list
                row without breaking the line, and legible at 0.7rem.
   .pn-prembox  the callout used when a whole window is gated, or when a limit
                applies. Reads as information, not as a warning: a premium
                feature is not an error, and colouring it red would say it is.

   Premium is the ACCENT here, not the alarm colour. Both tiers get the same
   shape, so the split reads as a fact about the product rather than a nag. */
.pn-tag{
  display:inline-flex;align-items:center;gap:.25rem;
  font-family:var(--mono);font-size:.64rem;font-weight:700;
  letter-spacing:.09em;text-transform:uppercase;
  border-radius:999px;padding:.12rem .5rem;
  border:1px solid var(--line);color:var(--muted);
  white-space:nowrap;vertical-align:.08em;margin-right:.35rem;
}
/* Free reads as the baseline: quiet, neutral. */
.pn-tag--free{border-color:var(--border-strong);color:var(--text-soft)}
/* Premium carries the accent and a small diamond. */
.pn-tag--prem{
  border-color:var(--accent);color:var(--accent);
  background:color-mix(in srgb, var(--accent) 14%, transparent);
}
.pn-tag--prem .pn-tag__mark{font-size:.72rem;line-height:1}

.pn-prembox{
  margin:.9rem 0 1rem;padding:.7rem .85rem;
  border:1px solid var(--line);border-left:3px solid var(--accent);
  border-radius:8px;background:rgba(110,86,207,.07);
}
.pn-prembox__head{
  display:flex;align-items:center;flex-wrap:wrap;gap:.1rem;
  margin:0 0 .35rem;font-size:.84rem;font-weight:700;color:var(--text);
}
.pn-prembox__free{
  margin:0;font-size:.79rem;line-height:1.55;color:var(--text-soft);
}
.pn-prembox__free strong{color:var(--text)}

/* ---------- Free and Premium, side by side ----------
   The Get SARAH window offers both tiers, and stacking them meant Premium sat
   below the fold and read as an afterthought. Two equal columns put the choice
   in front of someone instead of under them.

   auto-fit + minmax does the responsive work: with ~648px of content width the
   two columns get ~315px each; shrink the window, or hit the full-screen mobile
   sheet, and it collapses to a single column on its own. No breakpoint to keep
   in sync with the window sizes in lib/neural.php.

   15rem (240px) as the minimum means the collapse happens well BEFORE the
   contents get cramped, not at the last possible moment. */
.pn-cols{
  display:grid;gap:1rem 1.4rem;
  grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));
  align-items:start;margin:0 0 1rem;
}
.pn-col{min-width:0}

/* The Premium column is marked with the accent, matching .pn-tag--prem and the
   ◆ used on the Free/Premium labels elsewhere. A left rule rather than a filled
   card: a column is not an alert, and a heavy background here would fight the
   Buy buttons inside it, which are the thing that should stand out. */
.pn-col--prem{
  border-left:2px solid var(--accent);
  padding-left:.95rem;
}
/* On a narrow window the rule would sit above the content instead of beside it,
   so it becomes a top rule once the columns have collapsed. */
@media(max-width:660px){
  .pn-col--prem{
    border-left:0;border-top:2px solid var(--accent);
    padding-left:0;padding-top:.9rem;
  }
}

.pn-col h2{margin-top:0}
.pn-col__mark{color:var(--accent);font-size:.8em;margin-right:.25rem}

/* In a single column the rows keep their shape; in the narrow two-column grid
   the name and price crowd the button, so each gets its own line. */
.pn-col .pn-buy b{flex:1 1 100%}

/* MUST be shrinkable and must be allowed to break.
   `flex:0 0 auto` here was a real bug: flex-shrink:0 stops the item going below
   its max-content width, so a long value punched straight through the column and
   off the edge of the window (measured 1151px in a 309px column). The value is
   whatever an admin typed, and one install is already a full sentence in the
   version field, so assume it can be long. min-width:0 is what actually permits
   a flex item to shrink; overflow-wrap:anywhere covers a run with no spaces. */
.pn-col .pn-buy__price{
  flex:0 1 auto;min-width:0;margin-right:auto;
  overflow-wrap:anywhere;word-break:break-word;
}
/* Same reasoning for the note and the button label — both come from admin text. */
.pn-buy__note{overflow-wrap:anywhere;word-break:break-word}
.pn-buy b{overflow-wrap:anywhere;word-break:break-word}

/* The free column's rows have a version tag rather than a label; keep it from
   shoving the button sideways. */
.pn-col .pn-buy__plat{display:block}

/* ---------- form fields on touch: never smaller than 16px ----------
   iOS Safari ZOOMS THE WHOLE PAGE when you focus an input whose font-size is
   under 16px, and it does not zoom back out — so tapping the coupon box jumped
   the layout sideways and left the buyer scrolled off the form, mid-purchase.
   Every field here was 0.88rem (about 14px), which is exactly in the danger zone.

   16px is the threshold, not a style preference, so it is applied last and to
   every field rather than adjusted one by one. `!important` is not used: these
   rules come after the individual ones, and equal specificity means the later
   rule wins. The desktop keeps the tighter type because the rule is wrapped in
   a touch-width query AND a hover check, so a narrow desktop window is not
   affected either. */
/* html.is-touch is set by panels.js from the real capability, because
   `any-pointer: coarse` reports FALSE in some environments that are plainly
   touch (it did in the browser this was tested in), and a rule that silently
   never matches is worse than no rule — the fields simply stayed at 14px. The
   same declarations are repeated for the width-only case as a fallback, so a
   touch device with scripting off still gets them. */
@media(max-width:820px){
  .pn-form input,
  .pn-form textarea,
  .pn-form select,
  .pn-contact input,
  .pn-contact textarea,
  .pn-contact select,
  .mp-search input,
  .mp-search select,
  .mp-search .pn-mp-q,
  .card-form input:not([type=checkbox]):not([type=radio]),
  .card-form textarea,
  .card-form select {
    font-size:16px;
    min-height:44px;
  }
  .pn-contact textarea{min-height:9rem}
  /* A 44px hit area for the buttons people actually press on a phone. */
  .pn-btn,.pn-btn--buy{min-height:44px;padding:.6rem .8rem;font-size:.8rem}
  .pn-actions{gap:.6rem}
  .pn-actions .pn-btn{width:100%;justify-content:center}
}

/* The marketplace search field is a bare .pn-mp-q, not inside .pn-search, so it
   needs naming directly — it was the last 12.8px field left. */
.pn-mp-q{font-size:16px;min-height:40px}
@media(min-width:821px){
  /* Desktop keeps the denser type. */
  .pn-mp-q{font-size:.82rem;min-height:0}
}

/* ---------- the FREE download buttons ----------
   A few pixels bigger than the standard .pn-btn: they are the primary action in
   the Free column and a 0.72rem button is easy to miss. "A few pixels" is
   deliberate — a big green slab would shout, and the Buy buttons beside them
   should still read as the premium choice. */
.pn-btn--free{
  font-size:.8rem;
  padding:.5rem .75rem;
  color:var(--text);
  border-color:var(--border-strong);
}
.pn-btn--free:hover{color:#fff;border-color:var(--accent)}

/* ---------- "What Premium adds" ----------
   This is the SELLING POINT of the paid column, and it used to render as a
   0.72rem faint-grey footnote under the Buy button — technically present,
   practically invisible. It is now a proper block in the premium column:

     · type a step up from the panel body (0.84rem), not a footnote
     · full-strength text colour, not faint grey
     · its own small heading, so it reads as part of the offer
     · the accent left rule, tying it to the premium column's own marker

   Kept inside the column rather than spanning both: it belongs to the premium
   offer, and spanning would make it look like it applies to the free build too. */
.pn-prem__adds{
  margin:.55rem 0 .2rem;
  padding:.6rem .7rem .5rem;
  border-left:2px solid var(--accent);
  background:rgba(110,86,207,.06);
  border-radius:0 8px 8px 0;
}
.pn-prem__adds-head{
  font-family:var(--mono);font-size:.64rem;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;color:var(--accent);
  margin:0 0 .4rem;
}
.pn-prem__adds-row{
  margin:0 0 .3rem;font-size:.84rem;line-height:1.5;color:var(--text);
}
.pn-prem__adds-row:last-child{margin-bottom:0}
.pn-prem__adds-row b{
  display:block;font-size:.78rem;color:var(--accent);
  letter-spacing:.04em;margin-bottom:.05rem;
}
.pn-prem__adds-row span{color:var(--text-soft)}

/* ---------- feedback: the form, and the wall under it ----------
   The wall sits DIRECTLY below the form, as asked, and that order also reads
   better: you write, then you immediately see what everyone else wrote.

   Email is never shown — only name, rating and date. The address was given so we
   can reply, not for display, and printing it would turn this into a harvest. */
.pn-fb__avg{
  margin:.2rem 0 .9rem;font-size:.86rem;color:var(--text-soft);
  display:flex;align-items:baseline;gap:.4rem;flex-wrap:wrap;
}
.pn-fb__avg b{font-size:1.3rem;color:var(--text);line-height:1}
.pn-fb__avg span[aria-hidden]{color:#f0b429;letter-spacing:.06em}
.pn-fb__avg-n{font-size:.76rem;color:var(--faint)}

.pn-fb__wall-head{margin-top:1.3rem}

.pn-fb{margin:0;padding:0;list-style:none;border-top:1px solid var(--border)}
.pn-fb li{padding:.75rem 0;border-bottom:1px solid var(--border)}
.pn-fb__head{
  margin:0 0 .3rem;display:flex;align-items:baseline;gap:.5rem;flex-wrap:wrap;
}
.pn-fb__head b{color:var(--text);font-size:.85rem}
.pn-fb__stars{color:#f0b429;letter-spacing:.1em;font-size:.82rem}
.pn-fb__date{margin-left:auto;font-family:var(--mono);font-size:.7rem;color:var(--faint)}
.pn-fb__body{margin:0;font-size:.84rem;line-height:1.6;color:var(--text-soft);overflow-wrap:anywhere}

/* The rating select is a bare dropdown in a form; give it the same shape as the
   other fields so the form does not look half-finished. */
.pn-feedback select{
  font:inherit;font-size:.88rem;background:var(--sunk);border:1px solid var(--line);
  border-radius:7px;color:var(--text);padding:.45rem .55rem;width:100%;
}
.pn-feedback select:focus{outline:2px solid var(--accent);outline-offset:0;border-color:var(--accent)}
.pn-feedback textarea{
  font:inherit;font-size:.88rem;background:var(--sunk);border:1px solid var(--line);
  border-radius:7px;color:var(--text);padding:.5rem .55rem;width:100%;
  resize:vertical;min-height:7rem;line-height:1.5;
}
.pn-feedback input[type=text],.pn-feedback input[type=email]{
  font:inherit;font-size:.88rem;background:var(--sunk);border:1px solid var(--line);
  border-radius:7px;color:var(--text);padding:.45rem .55rem;width:100%;
}

/* Touch: 16px so iOS does not zoom the page on focus, and 44px targets. */
@media(max-width:820px){
  .pn-feedback select,.pn-feedback textarea,
  .pn-feedback input[type=text],.pn-feedback input[type=email]{font-size:16px;min-height:44px}
  .pn-feedback textarea{min-height:8rem}
}
