Find out if this a valid Stack Cats program, in Stack Cats style! Background

Stack Cats is a reversible esoteric language made by Martin Ender. Each command in Stack Cats is either the inverse of itself (represented as a symmetric character, such as -_:T|), or has its inverse command (represented as the mirror image, such as () {} [] &lt;&gt;). Stack Cats has a strong syntactic requirement that the whole program should be the mirror image of itself. Note that this means any valid Stack Cats program is a natural mirror-image ambigram.

Here is the whole command set of Stack Cats:


Self-symmetric: !*+-:=ITX^_|
Symmetric pairs: () {} [] &lt;&gt; \/


Any other characters are invalid; any input having a character not in the character set above should output false.

The language has additional constraint that () and {} pairs must be always balanced, but for the sake of simplicity, you don't have to check for this condition.

The following are some examples of a valid Stack Cats program (again, note that you don't check for balanced parens):

{[+]==[+]}
[)&gt;^&lt;(]
({T)}|{(T})
&lt;(*]{[:!-_:&gt;}&lt;[&lt;)*(&gt;]&gt;{&lt;:_-!:]}[*)&gt;


These are not:

b&lt;+&gt;d
())(
({[&lt;++&lt;]})


Challenge

Write a program or function that determines if the given string is a valid Stack Cats program. Your code should also be a natural mirror-image ambigram, which means:


Your code should be a mirror image of itself.


Your code may have one or more newlines, as long as the whole code, displayed naturally, is a mirror image of itself.
You can omit or add trailing whitespaces on each line, since it doesn't change the display.
Tab characters are not allowed since they have some ambiguity on display.



Note: your code does not have to be a valid Stack Cats program; it may contain certain extra characters that are not allowed in Stack Cats. (See below for the complete list.)

For example, the following two programs are symmetric (and thus a valid submission), while the third is not:

({bTd})
[&lt;q|p&gt;]

({bTd})
  IXI

({bTd})
IXI


Regarding "mirror symmetry", only Stack Cats-style symmetry is considered (e.g. ({IH}) is not a valid submission, even though it has mirror symmetry).
Your code can only contain these sets of characters, plus newline:


Self-symmetric: space (0x20) + !"'*+-.8:=AHIMOTUVWXY^_ovwx|
Symmetric pairs: () /\ &lt;&gt; [] bd pq {}



The character set is chosen to be strictly symmetric or self-symmetric when displayed as code on SE.

Input and Output

The input range is any one-line string of printable ASCII characters.

You can choose to take input as a string, a list of chars, or a list of ASCII values.

You can choose to output either:


Any of the truthy/falsy values as defined by the language of your choice


The actual result values may differ between inputs (e.g. output 1 for a truthy input and 2 for another truthy one).
Swapping truthy and falsy values is not allowed.

Any two constant values for true/false respectively


In this case, the result values should exactly be one of the two constant values.



You should specify your input method and output values in your submission.

Winning Condition

This is code-golf, so lowest bytes in each language wins.

Notes


Standard loopholes are forbidden as usual.
Of course you can solve this in Stack Cats, but the chance is that you can't use a flag that allows to reduce your code size by half. And it's seriously hard language to pick up :P
JavaScript (ES6), 487 467 378 298 292 280 266 264 bytes

Saved 14 bytes thanks to @Bubbler

I=&gt;(V=v=&gt;!I[v]||((T=o=&gt;[[]][+!!A[o]]||[(I[v]!=A[o]||A)[o^o&lt;88/8]]+T(++o))(8-8)==I.pop())*V(++v))(V|(A='(){}[]&lt;&gt;\\/ !*+-:=ITX^_|'))//\\(('|_^XTI=:-+*! \//&lt;&gt;[]{}()'=A)|V)((v++)V*(()qoq.I==(8-8)((o++)T+[[8\88&gt;o^o](A||[o]A=![v]I)]||[[o]A!!+][[]]&lt;=o=T))||[v]I!&lt;=v=V)&lt;=I


Defines an anonymous function that takes an array of chars and returns the desired output. Output is truthy/falsy; usually 1/0, but the empty string gives true.

How?

The most obvious trick is to use //\\ as a center point to comment out the mirrored version of the code. After that, it becomes a game of figuring out the shortest way to solve the problem using only the charset given.

The first issue we run into is the lack of keywords and built-ins. We miraculously still have .pop(), but everything else will have to be done via the allowed operators (which includes a[b] and f(c)), with recursion to emulate loops.

The second issue is the lack of logical operators. Neither &amp; and ? are allowed, which means the only decision-making operator we can use is ||. Therefore, we have to carefully structure our logic to account for this.

The first thing I did was to define a function T that mirrors an individual character. The basic idea is to loop through each character in a string of mirror-able chars, testing each for equality with the given char. If it is equal, we return its mirror&mdash;the char at index^1 for (){}[]&lt;&gt;\/, or the char itself for the rest.

The first problem I ran into here was getting either the mirrored char or a falsy value on each iteration. The solution I eventually came up with was (x!=A[o]||A)[o^o&lt;88/8], where x is the input character, A is the mirroring alphabet, and o is the current index. If x is not the same as A[o], this gives true, and the index expression evaluates to undefined; otherwise, the ||A is activated, and we end up getting A[o^(o&lt;11)].

The second problem is how to terminate the recursion. I found that the best way to do this is to simply concatenate the results of every iteration, returning the empty string when the end of A is reached. This presents us with two further problems: converting the undefineds to empty strings, and returning the empty string || something. These can be solved with array abuse: [a]+"" gives the string representation of a, or the empty string if a is undefined. As a bonus, [] is truthy but stringifies to the empty string, so we can conveniently use this as a "truthy empty string".

Now we can use the T function to mirror any single character. We do this recursively, comparing the mirror of I[v++] to I.pop() until the end of the array of chars is reached. We can't use &amp;&amp; or &amp; to check if all of the comparisons are truthy, but so use * instead. Multiplying all of these results together gives 1 if every character is the mirror of the one opposite, or 0 if any comparison fails.

And that is basically how this answer works. I probably didn't explain it very clearly, so please ask any questions you may have and point out any mistakes I have made.