Faits :
A.
La société Z._ SA (ci-après: la locataire) était liée à la société X._ Sàrl (ci-après: la bailleresse) par un contrat de bail à loyer portant sur l'usage d'un camion. Le 14 décembre 2012, un employé de la locataire a eu un accident entraînant l'immobilisation du véhicule loué. Par courrier électronique du 17 janvier 2013, la bailleresse a déclaré résilier le contrat de location pour le jour même.
B.
B.a. Le 30 juin 2014, la bailleresse a ouvert action contre la locataire devant le Tribunal civil du Littoral et du Val-de-Travers (NE), concluant au paiement de 19'078 fr. (18'078 fr. à titre de location pour la période du 1 er janvier 2013 au 18 mars 2013, 1'000 fr. à titre de remboursement de la franchise de l'assurance responsabilité civile). La locataire a conclu au rejet de l'action, estimant ne plus rien devoir à la bailleresse dès lors que celle-ci n'avait d'abord rien entrepris pour réparer le véhicule, puis avait profité de la réparation pour faire exécuter d'autres travaux sur le véhicule.
Par jugement du 15 janvier 2015, le Tribunal civil a condamné la locataire au paiement de 1'000 fr. (franchise) et rejeté les autres conclusions (prix de la location dès le 1 er janvier 2013). Il a jugé que le loyer n'était plus dû à partir du 18 janvier 2013 dans la mesure où la demanderesse avait résilié le contrat pour cette date; en outre, aucun loyer n'était dû pour la période antérieure, au motif que le montant convenu de 300 fr. par jour devait être payé en cas d'utilisation du véhicule, lequel était en l'occurrence inutilisable.
B.b. Statuant sur appel de la bailleresse, la Cour d'appel civile du Tribunal cantonal neuchâtelois a réformé le jugement par arrêt du 13 avril 2016. En sus des 1'000 fr. déjà alloués, elle a condamné la locataire à payer 3'600 fr. à titre de loyer pour la période du 1 er au 17 janvier 2013 (300 fr. par jour ouvrable). Contrairement au premier juge, la Cour d'appel a retenu que les décomptes produits ne permettaient pas d'inférer que la rémunération était perçue en fonction de l'utilisation effective du véhicule, alors que le camion était à disposition de la locataire, qu'elle l'utilise ou non. La rémunération convenue était de 300 fr. par jour ouvrable sans les samedis et restait due jusqu'à la résiliation du contrat de location, intervenue avec effet au 17 janvier 2013. La Cour d'appel a en revanche jugé que "les prétentions de la [bailleresse] à un loyer pour la période postérieure au 17 janvier 2013 ou à une indemnité de réparation pour le manque à gagner consécutif à l'immobilisation du véhicule au-delà de cette date [étaie]nt dénuées de tout fondement et d[e]v[ai]ent être rejetées".
C.
La bailleresse (ci-après: la recourante) a interjeté un recours en matière civile et, pour le cas où celui-ci devrait "d'aventure" être rejeté, un recours constitutionnel subsidiaire; elle conclut à ce que la locataire (ci-après: l'intimée) soit condamnée à lui payer, en sus des 1'000 fr. déjà alloués en première instance, 15'078 fr. avec intérêts moratoires de 5% l'an dès le 5 avril 2013 (18'078 fr. selon demande, desquels 3'000 fr. sont déduits pour dix jours de travaux effectués sur ordre de la recourante).
L'intimée a déposé une réponse dans laquelle elle conclut à l'irrecevabilité, subsidiairement au rejet du recours, suite à quoi la recourante a déposé des observations.
L'autorité précédente s'est référée à son arrêt.

Considérant en droit :
1.
Le contrat liant les parties est un bail mobilier. La valeur litigieuse déterminante devant le Tribunal fédéral correspond au montant resté litigieux devant l'instance précédente (<ref-law>), à savoir 18'078 fr. La voie du recours en matière civile est dès lors ouverte (<ref-law>) et le recours constitutionnel irrecevable (<ref-law>). Contrairement à ce que semble croire la recourante, cette voie subsidiaire ne dépend pas du point de savoir si le recours en matière civile est fondé ou non.
2.
La recourante se plaint d'abord d'une violation du droit d'être entendu, au motif que la Cour d'appel n'aurait pas motivé le rejet de sa prétention en indemnité pour usage de l'objet après l'échéance du contrat de bail, nonobstant le fait qu'elle avait invoqué les art. 266f et 267 al. 1 CO.
2.1. La recourante se prévaut de l'art. 28 al. 2 Cst./NE et de l'art. 29 al. 2 Cst., sans toutefois démontrer que la Constitution cantonale accorderait un droit plus étendu que la Constitution fédérale. Il n'y a donc pas à entrer en matière sur le grief relatif à la norme constitutionnelle cantonale.
L'intimée allègue que l'arrêt attaqué ne fait aucune mention de ce que la recourante aurait invoqué les art. 266f et 267 CO; cet état de fait procédural n'étant pas critiqué de manière circonstanciée par la recourante, elle conclut qu'il lie la cour de céans et que celle-ci ne saurait retenir que la recourante a invoqué les dispositions précitées. Or, la recourante a fait valoir un loyer - respectivement une indemnité - pour la période postérieure à la résiliation du contrat de location, au motif que l'objet loué n'avait pas été restitué. La Cour d'appel appliquant le droit d'office (<ref-law>), il importe peu que la partie appelante ait expressément invoqué une disposition légale dès lors qu'elle a allégué les faits sur lesquels elle fonde ses prétentions et qu'elle a pris des conclusions. Au demeurant, la recourante a expressément invoqué les art. 266f et 267 CO dans sa réplique adressée à la Cour d'appel.
2.2. Le droit d'être entendu garanti par l'art. 29 al. 2 Cst. implique notamment pour l'autorité l'obligation de motiver sa décision. Il suffit que le juge mentionne, au moins brièvement, les motifs qui l'ont guidé et sur lesquels il a fondé sa décision, de manière à ce que l'intéressé puisse se rendre compte de la portée de celle-ci et l'attaquer en connaissance de cause. L'autorité ne doit toutefois pas se prononcer sur tous les moyens des parties; elle peut se limiter à ceux qui, sans arbitraire, lui paraissent pertinents (<ref-ruling> consid. 5.1).
L'arrêt attaqué ne contient aucune motivation du rejet des prétentions en paiement d'une indemnité pour la période postérieure à l'échéance du contrat de location; l'arrêt se limite à l'affirmation que ces prétentions de la recourante sont dénuées de tout fondement. Le juge de première instance avait nié tout droit au loyer dès le 1 er janvier 2013, à savoir pour la période antérieure à la résiliation du contrat de location, au motif que le véhicule était inutilisable; il en découlait a fortiori qu'aucune indemnité pour le véhicule inutilisable n'était due après la résiliation du contrat de location. La motivation du juge de première instance est claire. Mais on ne saurait retenir que la Cour d'appel l'a implicitement fait sienne. En effet, contrairement au juge de première instance, elle a condamné l'intimée à payer le loyer jusqu'à la date de la résiliation du contrat, nonobstant le fait que le véhicule était hors d'usage; ce dernier point ne peut donc logiquement pas avoir été, dans l'esprit de la Cour d'appel, le motif du rejet des prétentions de la recourante pour la période postérieure à la résiliation. Les motifs de la Cour d'appel ne sont pas reconnaissables. Ils le sont d'autant moins que l'état de fait constaté par cette autorité, extrêmement succinct et insuffisant au regard de l'<ref-law>, ne porte notamment pas sur les détails de ce qui est survenu entre le 14 décembre 2012 et le 18 mars 2013, la Cour d'appel se contentant d'exposer les allégués des parties sans dire lesquels elle retient. Le grief est fondé.
3.
Il s'ensuit l'admission du recours, l'annulation de l'arrêt attaqué et le renvoi de la cause à la Cour d'appel, sans qu'il soit nécessaire d'examiner les autres griefs soulevés par la recourante. L'intimée, qui a conclu à l'irrecevabilité, respectivement au rejet du recours, succombe et supporte en conséquence les frais et dépens de la présente procédure (art. 66 et 68 LTF).

Par ces motifs, le Tribunal fédéral prononce :
1.
Le recours constitutionnel subsidiaire est irrecevable.
2.
Le recours en matière civile est admis.
3.
L'arrêt attaqué du 13 avril 2016 est annulé et la cause renvoyée à la Cour d'appel civile du Tribunal cantonal du canton de Neuchâtel.
4.
Les frais de la présente procédure, fixés à 2'000 fr., sont mis à la charge de l'intimée.
5.
L'intimée versera à la recourante une indemnité de 2'500 fr. à titre de dépens.
6.
Le présent arrêt est communiqué aux mandataires des parties et à la Cour d'appel civile du Tribunal cantonal du canton de Neuchâtel.
Lausanne, le 3 octobre 2016
Au nom de la Ire Cour de droit civil
du Tribunal fédéral suisse
La Présidente : Kiss
La Greffière : Monti