Faits: A. A.a. D._ est administrateur de plusieurs sociétés, dont X._ S.A., sise dans le canton de Neuchâtel. Il a entretenu différentes relations commerciales avec A.A._ et son fils B.A._, qui administrent aussi des personnes morales. B.A._est le gérant de Z._ Sàrl, société à responsabilité limitée de droit luxembourgeois, dont il possède la totalité du capital. De nombreux flux financiers ont eu lieu entre les sociétés de D._ (ou lui-même), d'une part, et B.A._ ou A.A._, d'autre part. En particulier, A.A._ a transféré à D._ la somme totale de EUR 200'000.00, par trois versements effectués entre septembre et décembre 2003. En 2005, Z._ Sàrl a soumis à X._ S.A. un document rédigé en allemand intitulé " Darlehensvertrag ", qui contenait notamment les clauses suivantes: "Vorbemerkung: Der Darlehensgeber und der Darlehensnehmer sind seit mehreren Jahrzehnten in unterschiedlichen Konstellationen gemeinsam geschäftlich tätig. Aufgrund dieser gemeinsamen Tätigkeiten gewährte der Darlehensgeber dem Darlehensnehmer in der Vergangenheit ein Darlehen in Höhe von derzeit insgesamt EUR 200'000.00. [...] § 1 Der Darlehensnehmer erkennt hiermit und zwar schuldbegründend durch diese Urkunde an, dem Darlehensgeber den in der Vorbemerkung genannten Betrag in Höhe von insgesamt EUR 200'000.00 zuzüglich Zinsen zu schulden (Siehe § 2). (nachfolgend Darlehen #1 genannt). § 2 Der in §1 anerkannte Betrag (Darlehen #1) ist ab dem 15.08.2005 mit 10% jährlich zu verzinsen. [...] § 3 Der in §1 anerkannte Betrag (Darlehen #1) ist spätestens am 30.12.2007 zur Rückzahlung fällig. [...] § 4 Zur Sicherung des Darlehen #1 hat der Darlehensnehmer dem Darlehensgeber bereits eine Briefhypothek an dem Hausgrundstück in Le Locle, [...] Hypothekenbrief [...] ...1, ausgehändigt [...]." Le contrat déclarait le droit suisse applicable. Ce document a été renvoyé à la société luxembourgeoise, signé par D._ en qualité d'administrateur unique de X._ S.A. et daté du 8 juillet 2005. Il avait toutefois biffé la clause suivante: " Des weiteren übernimmt Herr D._, nunmehr handelnd im eigenen Namen, die selbstschuldnerische Bürgschaft unter Verzicht auf die Einrede der Vorausklage für das Darlehen #1 in Höhe von EUR 200'000.00, zuzüglich der anfallenden Zinsen ". Le 19 septembre 2005, X._ S.A. a invité Z._ Sàrl à lui renvoyer le contrat de prêt signé avant le 26 septembre 2005, à défaut de quoi elle le considérerait comme annulé. Z._ Sàrl, qui avait reçu à une date indéterminée une cédule hypothécaire grevant en premier rang des parts PPE appartenant à X._ S.A., est restée en possession de ce gage. A.b. Z._ Sàrl a dénoncé le prêt le 28 février 2008. Dans un courrier du 4 mars 2008 rédigé par son avocat, D._ a répondu qu'il était "déterminé à régler ce qu'il d[eva]it à Z._ Sàrl"; toutefois, pour dégager les liquidités nécessaires, il proposait d'engager la cédule qui était en mains de ses cocontractants auprès d'un établissement bancaire lequel, dès réception de la cédule, leur virerait la somme de EUR 256'969.35. Dans un écrit du 25 juillet 2008 rédigé en allemand, le conseil de D._ a indiqué que son client ne savait en vérité plus s'il avait reçu le montant de EUR 200'000.00 à titre de prêt ou pour une autre cause; dans la mesure où les versements de Z._ étaient antérieurs à l'élaboration du "Darlehensvertrag", il fallait plutôt inférer qu'ils correspondaient à autre chose qu'un prêt. Aucun arrangement n'a pu être trouvé. Le 28 octobre 2008, Z._ Sàrl a intenté une poursuite en réalisation de gage à l'encontre de X._ S.A. Le commandement de payer portait sur le montant de CHF 432'607.90 plus intérêts à 5 % dès le 1er janvier 2008. Sous la rubrique "cause de l'obligation" figurait la mention suivante: "Montant dû au 31.12.2007 (EUR 256'969.35 taux de la BCN à cette date: 1.6835) sur la cédule hypothécaire au porteur de Fr. 500'000 (n° 1...) (....) ", cédule grevant en premier rang des parts PPE de X._ S.A. La société poursuivie a formé opposition. Par décision du 23 février 2009, le Tribunal civil du Locle a prononcé la mainlevée provisoire de l'opposition formée dans la poursuite n° yyy de l'Office des poursuites de La Chaux-de-Fonds, à concurrence de CHF 425'207.20 plus intérêts à 5 % dès le 7 mars 2008, tant à l'égard de la créance que du droit de gage. Le Tribunal cantonal a confirmé cette décision par arrêt du 19 juin 2009. B. B.a. Dans le cadre de cette poursuite, X._ S.A. a saisi la justice neuchâteloise le 17 mars 2009 d'une action en libération de dette et en paiement. Elle entendait faire constater qu'aucun contrat de prêt ne lie les parties et qu'elle ne doit pas la somme de CHF 432'607.90 (EUR 256'965.35) à Z._ Sàrl; elle prétendait en outre faire condamner cette dernière au montant de CHF 1'078'000.00. La société luxembourgeoise a conclu au rejet de l'action. Dans sa réplique, la demanderesse a invoqué la compensation. Par jugement du 29 mai 2012, le Tribunal civil des Montagnes et du Val-de-Ruz a rejeté l'action dans son entier. B.b. La société demanderesse a fait appel de cette décision, en maintenant ses conclusions visant à faire constater l'inexistence d'une dette de EUR 256'965.35 (CHF 432'607.90); en revanche, elle n'a pas contesté le rejet de l'action en paiement. Par arrêt du 19 février 2013, la Cour d'appel civile du Tribunal cantonal a confirmé le jugement. C. X._ S.A. saisit le Tribunal fédéral d'un recours en matière civile par lequel elle entend faire constater qu'elle n'est pas débitrice de la somme de EUR 256'965.35 (CHF 432'607.90) envers l'intimée, mais lui doit au maximum CHF 58'522.23. L'intimée Z._ Sàrl conclut au rejet du recours. L'autorité précédente se réfère aux motifs de son arrêt.